那必定是因为之后的 layout() 方法没有得到执行,导致 PFLAG_FORCE_LAYOUT 无法被清除。
欲探究竟,接着往下看。
如果你知道 requestLayout() 调用是一个层级调用,那么恭喜你,你已经处于认知的第一层了。送你一张二层入场券。
==================================================================================
我们来看看第一层讲到的 ViewRootImpl.requestLayout()。
//ViewRootImpl.java
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//1. 往主线程的Handler对应的MessageQueue发送一个同步屏障消息
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//2. 将mTraversalRunnable保存到Choreographer中
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
该方法主要作用如下:
-
往主线程的 Handler 对应的 MessageQueue 发送一个同步屏障消息;
-
将 mTraversalRunnable 保存到 Choreographer 中;
此处有三个特别重要的知识点:
-
mTraversalRunnable;
-
MessageQueue 的同步屏障;
-
Choreographer 机制;
mTraversalRunnable 相对比较简单,它的作用就是从 ViewRootImpl 从上往下执行 performMeasure()、performLayout()、performDraw()。
重点:它的执行时机是当 VSync 信号来到时,会往主线程的 Handler 对应的 MessageQueue 中发送一条异步消息,由于在 scheduleTraversals() 中给 MessageQueue 中发送过一条同步屏障消息,那么当执行到同步屏障消息时,会将异步消息取出执行。
===================================================================================
当 VSync 信号量到达时,Choreographer 会发送一个异步消息。当异步消息执行时,会触发 ViewRootImpl.mTraversalRunnable() 回调。
final class TraversalRunnable implements Runnable {
@Override