View#invalidate后,一定会调用当前child的onDraw
。这个方法跟 requestLayout
的区别在于,它不一定会触发 View 的 measure
和 layout
的操作,多数情况下只会执行 draw
操作。
我们从View#invalidate
开始,追一下调用流程。
1、View#invalidate:让当前的整个View无效。如果view可见,onDraw方法将在随后的某个节点调用。
/**
* Invalidate the whole view. If the view is visible,
* {@link #onDraw(android.graphics.Canvas)} will be called at some point in
* the future.
* <p>
* This must be called from a UI thread. To call from a non-UI thread, call
* {@link #postInvalidate()}.
*/
public void invalidate() {
invalidate(true);
}
2、View#invalidate(boolean invalidateCache):如果dimensions和content都相同,那么就可以跳过将drawing cache置为无效的步骤。
/**
* This is where the invalidate() work actually happens. A full invalidate()
* causes the drawing cache to be invalidated, but this function can be
* called with invalidateCache set to false to skip that invalidation step
* for cases that do not need it (for example, a component that remains at
* the same dimensions with the same content).
*
* @param invalidateCache Whether the drawing cache for this view should be
* invalidated as well. This is usually true for a full
* invalidate, but may be set to false if the View's contents or
* dimensions have not changed.
* @hide
*/
@UnsupportedAppUsage
public void invalidate(boolean invalidateCache) {
invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
}
3、child调用View#invalidate后,完整的调用流程:
--> View#invalidate
--> View#invalidate(boolean invalidateCache)
--> View#invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate):将Rect区域设置给AttachInfo#mTmpInvalRect
--> ViewGroup#invalidateChild(View child, final Rect dirty):默认开启了硬件加速,AttachInfo#mHardwareAccelerated为true
--> ViewGroup#onDescendantInvalidated(@NonNull View child, @NonNull View target)
--> ViewParent#onDescendantInvalidated(@NonNull View child, @NonNull View target):递归调用所有的parent
...
--> ViewRootImpl#onDescendantInvalidated(@NonNull View child, @NonNull View target)
--> ViewRootImpl#invalidate():
--> ViewRootImpl#scheduleTraversals()
--> ViewRootImpl#TraversalRunnable#run()
--> ViewRootImpl#doTraversal()
--> ViewRootImpl#performTraversals():cancelDraw为false
--> ViewRootImpl#performDraw()
--> ViewRootImpl#draw(boolean fullRedrawNeeded)
--> ThreadedRenderer#draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks):绘制DecorView
--> ThreadedRenderer#updateRootDisplayList(View view, DrawCallbacks callbacks)
--> ThreadedRenderer#updateViewTreeDisplayList(View view):读取PFLAG_INVALIDATED标记并给#View#mRecreateDisplayList赋值,然后清除PFLAG_INVALIDATED标记。
--> View#updateDisplayListIfDirty():用到了mRecreateDisplayList,此时mRecreateDisplayList为true。
--> DecorView#draw(Canvas canvas):
--> View#draw(Canvas canvas)
--> View#dispatchDraw(Canvas canvas)
--> ViewGroup#dispatchDraw(Canvas canvas)
--> ViewGroup#drawChild(Canvas canvas, View child, long drawingTime)
--> View#draw(Canvas canvas, ViewGroup parent, long drawingTime)
--> View#updateDisplayListIfDirty()
--> ViewGroup#dispatchDraw(Canvas canvas)
--> ViewGroup#drawChild(Canvas canvas, View child, long drawingTime)
...
最终调用到child的onDraw。因为在View#draw(Canvas canvas)
方法中,会调用View#onDraw(Canvas canvas)
。