Framework

View.post()不靠谱的地方你知道多少

2022-07-20  本文已影响0人  在岁月中远行

首先我们来看一段代码:

启动了两个模拟器 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方法来替代。

上一篇下一篇

猜你喜欢

热点阅读