看到记一次错误的使用View.post(Runnable)这篇的时候,自己去实验了一下,当时是在 Activity 的 onDestory 中做的,以为到了 onDestory View 肯定是 Detach 的,结果并不是这样的。。后来发现在 API 24的时候,关于 View.Post 这部分的代码有重写,所有就捋了捋关于这部分的东西,简单记录一下。

View Detach

View 什么时候才会 Detach ?当 View 中 mAttachInfo 这个变量置空的时候,就 Detach 了,是在 dispatchDetachedFromWindow 这个方法中置空的,这方法是在 ViewRootImpl.dispatchDetachedFromWindow() 中调用的,ViewRootImpl 可以看做是在 View 和 WindowManager 中间一个类 ,WMS 通过 IWindow 进行 ipc 通信控制通知客户端的 WindowManager, WindowManager 还要稍微使用 WindowManagerGlobal 中转处理一下,然后再去调用 ViewRootImpl 中的一些方法,而 ViewRootImpl 是持有 DecorView ,DecorView 中又有 WindowCallBack ,其实就是 Activity ,因为 Activity 实现了 WindowCallBack。这样再去调用 Activity 中关于 Window 相关的回调。回到问题,什么时候Detach? 当然还是在 Activity 销毁的时候,简单说下情形,A 启动 B ,在 B 中调用 finish。B finish-> B onPause->A onResume->B onStop->B onDestroy->B onDetachedFromWindow 。大致的流程是ActivityManagerNative通知AMS,AMS通过IApplicationThread调用ActivityThread.H去sendMessage,然后再去ActivityThread某个类似performPauseActivity,然后Instrumentation,然后就是activity生命周期。在最后调用handleDestroyActivity中,先调用ondestory 然后调用wm的removeViewImmediate,[ActivityThread.handleDestroyActivity() –>
WindowManager.removeViewImmediate() –>
WindowManagerGlobal.removeViewLocked()方法 —>
ViewRootImpl.die() –> doDie() –>
ViewRootImpl.dispatchDetachedFromWindow()],这个时候view.attachInfo 置空,所以当回调 Activity 的 onDestory 的时候,还没去调用 dispatchDetachedFromWindow ,当然还没 Detach 。关于 View 什么时候 Attached ,是在 onResume 之后,具体就不说了,和上面差不多。

View.post

说一下现象,当在 Attached 的时候,使用 View.post 就是走 handler 那一套,使用的 handelr 是 ViewRootImpl 中的 ViewRootHandler ,looper 就是 mainLooper ,这个没什么好分析的,这个时候怎么post都是有回调的。当在 Detach 的时候,

1
2
3
4
5
6
7
8
9
10
11
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}

走下面的 getRunQueue().post(action); 这个在24 以前 看开头那篇分析,是用 ThreadLocal 来进行的线程隔离,在 24 的时候,getRunQueue 变成了view的私有变量 mRunQueue:HandlerActionQueue ,当post 到这个里面去的时候,基本上是不会在调用了,因为它的 mRunQueue.executeActions(info.mHandler);是在 dispatchAttachedToWindow 中调用的。。一个activity生命周期只会调一次,也基本上用不到什么自行车了。。

PS

看下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
protected void onDestroy() {
super.onDestroy();
new Thread(new Runnable() {
@Override
public void run() {
button.post(new Runnable() {
@Override
public void run() {
Log.e("ssssss", "onDestroy");
}
});
}
}).start();
}

这里面的Log会不会调用??说实话,看缘分。。。不信自己去试试