-
invalidate
用于进行View的刷新,在UI线程调用
-
postinvalidate
用于进行View的刷新,在非UI线程调用,将非UI线程切换到UI线程,最后也是调用invalidate
postinvalidate源码解析
public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource {
...
public void postInvalidate() {
postInvalidateDelayed(0);
}
public void postInvalidate(int left, int top, int right, int bottom) {
postInvalidateDelayed(0, left, top, right, bottom);
}
public void postInvalidateDelayed(long delayMilliseconds) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds);
}
}
...
}
-
说明:可以看到postInvalidate()会调用postInvalidateDelayed(),最终会调用mViewRootImpl.dispatchInvalidateDelayed()方法
public void dispatchInvalidateDelayed(View view, long delayMilliseconds) { Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view); mHandler.sendMessageDelayed(msg, delayMilliseconds); } final class ViewRootHandler extends Handler { @Override public String getMessageName(Message message) { switch (message.what) { case MSG_INVALIDATE: return "MSG_INVALIDATE"; ... } return super.getMessageName(message); } ... @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_INVALIDATE: ((View) msg.obj).invalidate(); break; ... } } }
-
说明:在dispatchInvalidateDelayed中会通过Handler发送一个延迟消息,最终会调用View.invalidate()方法,在主线程中重新对View进行绘制
invalidate源码解析
public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource {
...
public void invalidate() {
invalidate(true);
}
//invalidateCache为true表示全部重绘
void invalidate(boolean invalidateCache) {
invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
}
void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
boolean fullInvalidate) {
...
if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
|| (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)
|| (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED
|| (fullInvalidate && isOpaque() != mLastIsOpaque)) {
if (fullInvalidate) {
mLastIsOpaque = isOpaque();
mPrivateFlags &= ~PFLAG_DRAWN;
}
mPrivateFlags |= PFLAG_DIRTY;
if (invalidateCache) {
mPrivateFlags |= PFLAG_INVALIDATED;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
}
//重点就在这里!!!
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
if (p != null && ai != null && l < r && t < b) {
final Rect damage = ai.mTmpInvalRect;
damage.set(l, t, r, b);
p.invalidateChild(this, damage);
}
...
}
}
}
-
说明:invalidate()会调用invalidateInternal()方法,在invalidateInternal中通过调用View的父布局invalidateChild方法来请求重绘
@Override public final void invalidateChild(View child, final Rect dirty) { ViewParent parent = this; final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { ... //这里省略了一些重新计算绘制区域的逻辑 //这是一个从当前的布局View向上不断遍历当前布局View的父布局,最后遍历到ViewRootImpl的循环 do { View view = null; if (parent instanceof View) { view = (View) parent; } if (drawAnimation) { if (view != null) { view.mPrivateFlags |= PFLAG_DRAW_ANIMATION; } else if (parent instanceof ViewRootImpl) { ((ViewRootImpl) parent).mIsAnimating = true; } } ... //这里调用的是父布局的invalidateChildInParent方法 parent = parent.invalidateChildInParent(location, dirty); ... } while (parent != null); } } @Override public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) { if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN || (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) { if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) != FLAG_OPTIMIZE_INVALIDATE) { ... //这里也是一些计算绘制区域的内容 return mParent; } else { mPrivateFlags &= ~PFLAG_DRAWN & ~PFLAG_DRAWING_CACHE_VALID; ... //这里也是一些计算绘制区域的内容 return mParent; }
}
return null;
}
-
在 @Override
public final void invalidateChild(View child, final Rect dirty) {
ViewParent parent = this;final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
…
//这里省略了一些重新计算绘制区域的逻辑//这是一个从当前的布局View向上不断遍历当前布局View的父布局,最后遍历到ViewRootImpl的循环 do { View view = null; if (parent instanceof View) { view = (View) parent; } if (drawAnimation) { if (view != null) { view.mPrivateFlags |= PFLAG_DRAW_ANIMATION; } else if (parent instanceof ViewRootImpl) { ((ViewRootImpl) parent).mIsAnimating = true; } } ... //这里调用的是父布局的invalidateChildInParent方法 parent = parent.invalidateChildInParent(location, dirty); ... } while (parent != null);
}
}
@Override
public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
(mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
FLAG_OPTIMIZE_INVALIDATE) {
...
//这里也是一些计算绘制区域的内容
return mParent;
} else {
mPrivateFlags &= ~PFLAG_DRAWN & ~PFLAG_DRAWING_CACHE_VALID;
...
//这里也是一些计算绘制区域的内容
return mParent;
}
}
return null;
}
-
说明:在invalidateChild中会有一个循环,循环里面会一直调用父布局的invalidateChildInParent方法,这样发现最终会调用ViewRootImpl的invalidateChildInParent方法
public final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks { //如果View没有父布局,那invalidateInternal方法就会调用这个方法 @Override public void invalidateChild(View child, Rect dirty) { invalidateChildInParent(null, dirty); } //ViewGroup的invalidateChild方法最后会调用到这里 @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { checkThread(); //如果dirty为null就表示要重绘当前ViewRootImpl指示的整个区域 if (dirty == null) { invalidate(); return null; //如果dirty为empty则表示经过计算需要重绘的区域不需要绘制 } 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 (!mWillDrawSoon && (intersected || mIsAnimating)) { //调用scheduleTraversals方法进行绘制 scheduleTraversals(); } } //绘制整个ViewRootImpl区域 void invalidate() { mDirty.set(0, 0, mWidth, mHeight); if (!mWillDrawSoon) { //调用scheduleTraversals方法进行绘制 scheduleTraversals(); } } }
-
在ViewRootImpl的invalidateChildInParent()方法中我们会发现他会调用invalidateRectOnScreen()方法,那在invalidateRectOnScreen中会调用 scheduleTraversals()
//ViewRootImpl.class void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); //关键在这里!!! mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } }
//ViewRootImpl.class
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);if (mProfile) { Debug.startMethodTracing("ViewAncestor"); } //找到我们的performTraversals方法来,这里就是开始绘制View的地方啦! performTraversals(); if (mProfile) { Debug.stopMethodTracing(); mProfile = false; } }
}
- 说明:在scheduleTraversals中会通过callback实现runable接口,在runable中最终调用performTraversals()执行重绘操作