invalidate() postInvalidate()php
requestLayout()java
看看invalidate源碼,以下所示git
public void invalidate() { invalidate(true); } public 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 (mGhostView != null) { mGhostView.invalidate(true); return; } if (skipInvalidate()) { return; } 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; } //這個地方是重點邏輯,主要分析這個 // Propagate the damage rectangle to the parent view. 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); } // Damage the entire projection receiver, if necessary. if (mBackground != null && mBackground.isProjected()) { final View receiver = getProjectionReceiver(); if (receiver != null) { receiver.damageInParent(); } } } }
看看ViewGroup中的invalidateChild方法github
@UiThread public abstract class ViewGroup extends View implements ViewParent, ViewManager { @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; } //這裏調用的是父佈局的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; } }
View中的invalidateChild方法和ViewGroup中的invalidateChildInParent方法最後異曲同工,都會調用到ViewRootImpl中的方法面試
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; } 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中的scheduleTraversals方法segmentfault
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } }
來看看TraversalRunnable這個類作了什麼?markdown
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(); if (mProfile) { Debug.stopMethodTracing(); mProfile = false; } } }
大概總結一下數據結構
先來看看View中的postInvalidate方法多線程
@UiThread 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方法最後調用了ViewRootImpl的dispatchInvalidateDelayed方法ide
//發送消息 //更多內容:https://github.com/yangchong211 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; } } }
大概總結一下
源碼以下所示
//View.class @CallSuper public void requestLayout() { if (mMeasureCache != null) mMeasureCache.clear(); if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { // Only trigger request-during-layout logic if this is the view requesting it, // not the views in its parent hierarchy ViewRootImpl viewRoot = getViewRootImpl(); if (viewRoot != null && viewRoot.isInLayout()) { if (!viewRoot.requestLayoutDuringLayout(this)) { return; } } mAttachInfo.mViewRequestingLayout = this; } //設置PFLAG_FORCE_LAYOUT標記位,這樣就會致使從新測量和佈局 mPrivateFlags |= PFLAG_FORCE_LAYOUT; //設置PFLAG_INVALIDATED就會進行從新繪製 mPrivateFlags |= PFLAG_INVALIDATED; if (mParent != null && !mParent.isLayoutRequested()) { //不斷調用上層View的requestLayout方法 mParent.requestLayout(); } if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { mAttachInfo.mViewRequestingLayout = null; } }
而後看看ViewRootImpl中的requestLayout方法
@Override public void requestLayout() { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); } }
而後再看看measure測量方法
public final void measure(int widthMeasureSpec, int heightMeasureSpec) { final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; if (forceLayout || needsLayout) { // first clears the measured dimension flag mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); if (cacheIndex < 0 || sIgnoreMeasureCache) { //調用onMeasure方法 onMeasure(widthMeasureSpec, heightMeasureSpec); mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } else { long value = mMeasureCache.valueAt(cacheIndex); setMeasuredDimensionRaw((int) (value >> 32), (int) value); mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } //設置PFLAG_LAYOUT_REQUIRED標記位,用於layout方法 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; } }
再而後看看layout方法
public void layout(int l, int t, int r, int b) { //因爲measure方法中設置了PFLAG_LAYOUT_REQUIRED標記位,因此會進入調用onLayout方法進行佈局流程 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { onLayout(changed, l, t, r, b); if (shouldDrawRoundScrollbar()) { if(mRoundScrollbarRenderer == null) { mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); } } else { mRoundScrollbarRenderer = null; } //取消PFLAG_LAYOUT_REQUIRED標記位 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; ListenerInfo li = mListenerInfo; if (li != null && li.mOnLayoutChangeListeners != null) { ArrayList<OnLayoutChangeListener> listenersCopy = (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); int numListeners = listenersCopy.size(); for (int i = 0; i < numListeners; ++i) { listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); } } } //取消PFLAG_FORCE_LAYOUT標記位 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; }
連接WindowManager和DecorView的紐帶,另外View的繪製也是經過ViewRootImpl來完成的。