invalidate()源码分析
invalidate()方法的使用,就是重新觸發一次View的繪制流程。
入口在View類中,
public void invalidate() {invalidate(true);
}public void invalidate(boolean invalidateCache) {invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
}
在 invalidateInternal(...) 中 ,調用
p.invalidateChild(this, damage); //p為ViewParent
ViewGroup繼承View,實現了 ViewParent,在ViewGroup的invalidateChild()方法中有個do while 循環,循環中關鍵代碼:
parent = parent.invalidateChildInParent(location, dirty);
ViewRootImpl實現了ViewParent,在ViewRootImpl中,
@Override
public void invalidateChild(View child, Rect dirty) {invalidateChildInParent(null, dirty);
}@Override
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {checkThread();if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);if (dirty == null) {invalidate();return null;} else if (dirty.isEmpty() && !mIsAnimating) {return null;}if (mCurScrollY != 0 || mTranslator != null) {mTempRect.set(dirty);dirty = mTempRect;if (mCurScrollY != 0) {dirty.offset(0, -mCurScrollY);}if (mTranslator != null) {mTranslator.translateRectInAppWindowToScreen(dirty);}if (mAttachInfo.mScalingRequired) {dirty.inset(-1, -1);}}invalidateRectOnScreen(dirty);return null;
}private void invalidateRectOnScreen(Rect dirty) {final Rect localDirty = mDirty;if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {mAttachInfo.mSetIgnoreDirtyState = true;mAttachInfo.mIgnoreDirtyState = true;}// Add the new dirty rect to the current onelocalDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);// Intersect with the bounds of the window to skip// updates that lie outside of the visible regionfinal float appScale = mAttachInfo.mApplicationScale;final boolean intersected = localDirty.intersect(0, 0,(int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));if (!intersected) {localDirty.setEmpty();}if (!mWillDrawSoon && (intersected || mIsAnimating)) {scheduleTraversals();}
}
invalidateChild(..)方法調用invalidateChildInParent(..),
invalidateChildInParent(..)方法調用invalidateRectOnScreen(dirty),
invalidateRectOnScreen(dirty)方法中最終會調用scheduleTraversals()
scheduleTraversals()這個方法很關鍵,會通過一系列的調用最終調用TraversalRunnable.run()方法,然后調用doTraversal()方法,doTraversal()中調用performTraversals()。
void doTraversal() {if (mTraversalScheduled) {mTraversalScheduled = false;mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);if (mProfile) {Debug.startMethodTracing("ViewAncestor");}performTraversals();if (mProfile) {Debug.stopMethodTracing();mProfile = false;}}
}
performTraversals()主要做三件事:
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
performLayout(lp, mWidth, mHeight);
performDraw();
最后會調用View的繪制方法:
measure(childWidthMeasureSpec, childHeightMeasureSpec);
layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
draw(fullRedrawNeeded);
至此,整個invalidate()流程結束,貫穿著一個布局或View的所有子view,以下是流程圖:
?
?
總結
以上是生活随笔為你收集整理的invalidate()源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android自定义View基本步骤
- 下一篇: 画笔Paint的使用