View的invalidate()过程

整理一下invalidate()方法的执行过程,下面贴的代码都是只保留了需要留意的部分,
标注了要注意的地方,一目了然。
先总结一下,invalidate()就是使界面只进行重绘(draw)而不进行measure、layout过程。

View中:

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) {
            ......
            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);  //这里
            }
            ......
}

ViewGroup

public final void invalidateChild(View child, final Rect dirty) {
        ......
        ViewParent parent = this;
        ......
        do {
        ......
        parent = parent.invalidateChildInParent(location, dirty);  //这里
        ......
        } while (parent != null);
}
public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
        if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID)) != 0) {
        ......
        return mParent;  //这里
        }

        return null;
    }

循着mParent一直调用到ViewRoot

ViewRootImpl

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;
        }
        ......
        invalidateRectOnScreen(dirty);    //这里
        return null;
}
    private void invalidateRectOnScreen(Rect dirty) {
        ......
        if (!mWillDrawSoon && (intersected || mIsAnimating)) {
            scheduleTraversals();
        }
    }

下面注意mTraversalRunnable变量,看看是什么类型哪里赋值的

void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); //这里
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
   final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();    //这里
        }
    }
    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

是一个Runnable,注意run中调用的方法。

void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }

            performTraversals();    //!这里!

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }

performTraversals()方法就是分法measure、layout、draw过程的地方,下面的代码比较长但是我们只需要留意invalidate()为什么只调用了draw而省略了测量布局过程。
注意invalidate()调用过程中没有设置mLayoutRequested,所以默认是false,进而方法里的局部变量insetsChanged也没有变true的机会了,然后导致后面if判断的时候无法进入measure和layout的执行流程。

private void performTraversals() {
        ......
        boolean insetsChanged = false;

        boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
        if (layoutRequested) {
            ......    //这里有几个判断,可能会把instsChanged设置为true
        }
        ......
        if (mFirst || windowShouldResize || insetsChanged ||
                viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
            ......
            if(...) {
                if(...) {
                    ......
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                    ......
                }
            }
        }
        ......
        final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
        boolean triggerGlobalLayoutListener = didLayout
                || mAttachInfo.mRecomputeGlobalAttributes;
        if (didLayout) {
            performLayout(lp, mWidth, mHeight);
            ......
        }
        ......
        if (!cancelDraw && !newSurface) {
            ......
            performDraw();
        }
        ......
}

你可能感兴趣的:(View的invalidate()过程)