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)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tinyvampirepudge

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值