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

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

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#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)

相关文章
|
XML Android开发 数据格式
进入Activity时,为何页面布局内View#onMeasure会被调用两次?
进入Activity时,为何页面布局内View#onMeasure会被调用两次?
调用View#requestLayout后,哪些View会被影响?
调用View#requestLayout后,哪些View会被影响?
|
Android开发
Android | View & Fragment & Window 的 getContext() 一定返回 Activity 吗?
Android | View & Fragment & Window 的 getContext() 一定返回 Activity 吗?
117 0
Android | View & Fragment & Window 的 getContext() 一定返回 Activity 吗?
|
XML 前端开发 数据格式
默认状态下,ViewGroup为什么不走onDraw()?
两种代码相同的自定义ViewGroup,只是改变了在xml中ViewGroup的背景,一个就会调用onDraw而另外一个则不会,那么为什么在不改变ViewGroup的情况下不走onDraw方法呢?那么又该如何解决这个问题??
283 1
|
前端开发 容器
05.源码阅读(View的invalidate,postInvalidate和requestLayout)
关键词:View ViewGroup ViewRootImpl invalidate是如何刷新view的? View /** * 必须可见才能刷新,运行于UI线程 * Invalidate the whole view.
1075 0