以android Q的源码为例子,一步步分析invalidate的调用流程。
在写自定义控件的时候时常会用到 invalide 方法,都知道调用 invalide 后会回调Draw方法,但其中的辗转历程鲜有人知,为了搞清这个流程,我从android Q 源码入手分析了整个调用流程。在此记录一下,省得以后忘了
1.App Call SufaceFlinger
1.任何的View的invalidate方法最终都会调用到ViewRootImpl.java的invalidate()或者invalidateChildInParent,区别只是mDirty的大小,这个mDirty表示这个区域需要重绘
frameworks/base/core/java/android/view/ViewRootImpl.java
1 2 3 4 5 6 7 8 |
void invalidate() { mDirty.set(0, 0, mWidth, mHeight); if (!mWillDrawSoon) {//在performTraversals 开始阶段赋值,结束的时候取消 scheduleTraversals(); } } |
2.scheduleTraversals的实现如下
frameworks/base/core/java/android/view/ViewRootImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();//插入同步屏障,此时只有异步message可以执行,目的是为了防止app占用消息队列导致消息循环延迟,这个Barrier必须在取消Traversals或者执行Traversals的时候移除,否则会出普通消息无法循环的情况 mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); //往mChoreographer 注册一个callbck if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } } |
3.这里需要注意的是一个插入同步屏障的过程,插入同步屏障后,只有异步的消息才能在MessageQeue循环,app这边 Handler之类的全部失去效果,所以在Traversals执行或者取消的时候会马上移除,如下所示