一、作用
`invalidate()` 方法的核心作用为对当前标记的View进行重绘。当 View 的内容发生改变(比如颜色、形状、位置等变化)时,调用该方法会触发 View 的绘制流程,系统会重新调用 `onDraw()` 方法来更新 View 的显示。需注意,invalidate()方法必须作用于主线程,若在子线程中调用应使用postInvalidate()来通过Handler切换至主线程。
二、源码解析
1.View类的invalidate方法

使整个视图失效。

该方法用于控制绘图缓存是否失效

将当前View需要重绘的区域传递给父容器
2.ViewGroup类中invalidateChild()方法
![]()
通过处理子View的重绘请求,通过invalidateChildInParent,递归向上传递重绘区域,直到传递至ViewRootImpl。
3.最终到ViewRootImpl处理
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
checkThread();
//…
invalidateRectOnScreen(dirty);
return null;
}
checkThread()方法用于检测当前线程是否为子线程,否则会触发异常报错。

private void invalidateRectOnScreen(Rect dirty) {
//…
if (!mWillDrawSoon && (intersected || mIsAnimating)) {
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
通过Choreographer触发后续操作
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
紧接着通过doTraversal()触发performTraversals()方法
private void performTraversals() {
//…
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); //测量
performLayout(lp, mWidth, mHeight); // 布局
performDraw(); // 绘制(最终调用 View.onDraw())
}
最后通过核心绘制流程measure、layout和draw完成重新绘制。其中performDraw()是最终绘制流程,也是invalidate()的最终环节。
4.performDraw()
draw -> drawSoftware
performDraw()真正的绘制逻辑在该方法中
最终通过mView.draw(canvas)触发View树的绘制,但在目前所绘制的区域在最外层,其中分为三步,分别为onDraw(canvas)绘制自身、dispatchDraw(canvas)绘制子View以及onDrawForeground(canvas)绘制背景。
602

被折叠的 条评论
为什么被折叠?



