首先我们来看一段代码:
启动了两个模拟器 API 22 和API 26分别是安卓7.0以下和安卓7.0以上
下面我们就从源码分析他们之间的差别以及为啥造成的现象不同
首先我们来分析安卓7.0以下的源码流程:
当attachInfo为空时走的是ViewRootImpl.getRunQueue().post(action);代码 当attachInfo不为空时,API26上下没区别。
ViewRootImpl可以理解是一个Activity的ViewTree的根节点的实例。每个ViewRootImpl就是用来管理DecorView和ViewTree。
ViewRootImpl的用来承载Runnable的队列是sRunQueues,它是一个静态变量,也就是说在APP的生命周期内,ViewRootImpl中的消息队列就是这一个。
我们再来看看前面提到的ViewRootImpl.getRunQueue.post()到底干了什么?
接下来我们再看哪里消耗mActions里面的Runnable
继续看executeActions在哪调用的
可以发现android.view.ViewRootImpl#performTraversals调用到的,而performTraversals()又是在android.view.ViewRootImpl#doTraversal调用的,它又是在
在TraversalRunnable中执行,
所以在API23以下,executeAction() 是会被循环调用,基本上其内的mActions只要有未执行的Runnable立刻就会被消耗掉。
所以在API23以下的设备上,View.post基本上是靠谱的,post出去的都是有机会执行的。
接下来分析API24的实现细节
同样类似的和API24以下,关键看下executeActions在哪执行,直接按住ctrl加上鼠标左键单击
既然executeActions()方法,在API24以上,只有在dispatchAttachedToWindow() 方法中,才有机会被调用到,而View.dispatchAttachedToWindow()方法,只有在View通过 addView()等方法中加入到一个ViewGroup的时候,才会被调用到,这就导致直接写在Layout 布局中的控件没有被addView的话,那么它永远也不会执行。这就导致现象不一致的缘故。
注意:上述都是分析的是 mAttachInfo 已经为空的情况,不为空是没有区别的。
可以尽量避免使用View.post()方法,直接使用Handler.post方法来替代。
网友评论