View.post는 Android 7.0 api24(이상)에서 100% 더 이상 수행되지 않음
11794 단어 여간하다
인스턴스
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mTv1.setText(" Handler Message");
}
};
private void btn2Click() {
final View view = new View(this);
Log.d("liuyz:", " :" + Build.VERSION.SDK_INT);
view.post(new Runnable() {
@Override
public void run() {
Log.d("liuyz:", " View post");
}
});
//Handler 2
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Log.d("liuyz:", "ViewGroup addView()");
mRoot.addView(view);
}
}, 2000);
}
간단합니다. View를 만들고 View를 직접 호출합니다.post (), 하나는Handler를 통과합니다.post()는 ViewGroup 실행을 2초 지연합니다.addView() 메서드.
api23에서Handler를 주석하지 않으면post() 메서드의 mRoot.addView(view)일 때 결과를 인쇄합니다.
com.cn.liuyz.customviewdemo D/liuyz:: :23
com.cn.liuyz.customviewdemo D/liuyz:: View post
com.cn.liuyz.customviewdemo D/liuyz:: ViewGroup addView()
주석을 달아버리면Handler.post() 메서드의 mRoot.addView(view)일 때 결과를 인쇄합니다.
com.cn.liuyz.customviewdemo D/liuyz:: :23
com.cn.liuyz.customviewdemo D/liuyz:: View post
api24에서Handler를 주석하지 않으면post() 메서드의 mRoot.addView(view)일 때 결과를 인쇄합니다.
com.cn.liuyz.customviewdemo D/liuyz:: :24
com.cn.liuyz.customviewdemo D/liuyz:: ViewGroup addView()
com.cn.liuyz.customviewdemo D/liuyz:: View post
주석을 달아버리면Handler.post() 메서드의 mRoot.addView(view)일 때 결과를 인쇄합니다.
com.cn.liuyz.customviewdemo D/liuyz:: :24
com.cn.liuyz.customviewdemo D/liuyz:: ViewGroup addView()
이로써 안드로이드 7.0 api24의 휴대전화에서 사용자 정의 View가addView()를 통해 View 그룹에 가입하지 않으면view를 알 수 있다.post () 의 작업이 더 이상 실행되지 않습니다
Android 7.0 소스 분석
View.post 소스
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
//
getRunQueue().post(action);
return true;
}
AttachInfo가 비어 있지 않으면 Handler를 호출합니다.post () 임무 수행, 그건 할 말이 없어요.AttachInfo가 비어 있을 때, 정부에서 준 주석은 AttachInfo가 이따가 성공적으로 실행될 것이라고 가정합니다. 즉, 실행하지 않을 수도 있습니다.
그럼 다음은 어떻게 안 하는지 볼게요.
getRunQueue 메서드
private HandlerActionQueue getRunQueue() {
if (mRunQueue == null) {
mRunQueue = new HandlerActionQueue();
}
return mRunQueue;
}
HandlerActionQueue 객체 반환
post() 방법 다시 보기
public void post(Runnable action) {
postDelayed(action, 0);
}
public void postDelayed(Runnable action, long delayMillis) {
// HandlerAction
final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
synchronized (this) {
if (mActions == null) {
// 4
mActions = new HandlerAction[4];
}
// HandlerAction
mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
mCount++;
}
}
post 방법은 작업을handlerAction 대상에 봉인하고handlerAction 그룹에 추가하여 실행할 때 순환을 통해 작업을 수행하는 것입니다.
그럼 최종적으로 임무를 처리하는 방법을 봅시다.
public void executeActions(Handler handler) {
synchronized (this) {
final HandlerAction[] actions = mActions;
for (int i = 0, count = mCount; i < count; i++) {
final HandlerAction handlerAction = actions[i];
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
mActions = null;
mCount = 0;
}
}
작업을 처리할 때,excuteActions 방법을 호출합니다. for 순환을 통해handlerAction 대상에 봉인된 작업을 실행하고, 마지막 작업의 실행은handler를 통합니다.postDelayed () 실행도 Handler의 메커니즘입니다.
그것도 믿음직스러워 보이는데 왜 100% 집행이 아니죠?아래를 보세요.
excuteActions 메서드는 View의 dispatchAttachedToWindow () 메서드에서 호출됩니다.
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
.... ....
if (mRunQueue != null) {
mRunQueue.executeActions(info.mHandler);
mRunQueue = null;
}
.... ....
}
dispatch Attached ToWindow 방법의 호출입니다. View Group에 의존하는ddView (View child) 방법입니다. 원본 코드를 보십시오.
public void addView(View child) {
addView(child, -1);
}
public void addView(View child, int index) {
.... ....
addView(child, index, params);
}
public void addView(View child, int index, LayoutParams params) {
.... ....
addViewInner(child, index, params, false);
}
private void addViewInner(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
.... ....
AttachInfo ai = mAttachInfo;
if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
boolean lastKeepOn = ai.mKeepScreenOn;
ai.mKeepScreenOn = false;
// View
child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
if (ai.mKeepScreenOn) {
needGlobalAttributesUpdate(true);
}
ai.mKeepScreenOn = lastKeepOn;
}
.... ....
}
여기를 보면 조금은 알아볼 수 있겠지. 사실 안드로이드 7.0 이후에는 View를 사용하지 말라는 것만 기억하면 돼.post입니다.Handler를 사용합니다.post 또는 다른 방식으로 대체하면 됩니다
총결산
new 또는 Layout Inflater를 사용하여 View를 만들고ddView()를 통해 View Group 레이아웃에 추가하지 않으면 View.post () 에서 실행되는 Runnable 작업은 실행되지 않고 UI 업데이트도 수행되지 않습니다.