View#invalidate是如何调用当前View#onDraw方法的?

824 阅读2分钟

View#invalidate后,一定会调用当前child的onDraw。这个方法跟 requestLayout 的区别在于,它不一定会触发 View 的 measurelayout 的操作,多数情况下只会执行 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#mHardwareAcceleratedtrue

--> 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():cancelDrawfalse

--> 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,此时mRecreateDisplayListtrue--> 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)