美文网首页
invalidate和postInvalidate使用场景及源码

invalidate和postInvalidate使用场景及源码

作者: 刘孙猫咪 | 来源:发表于2018-12-08 16:04 被阅读0次
    invalidate.png

    invalidate

    在自定view时,经常要调用invalidate方法去刷新ui,调用简单的invalidate方法就可以将ui重新刷新,其实在源码中相当多的处理,接下来就慢慢去看看invalidate方法的源码;在调用invalidate方法后就会去调用View中invalidate方法,

    /**
         * Invalidate the whole view. If the view is visible,
         * {@link #onDraw(android.graphics.Canvas)} will be called at some point in
         * the future.
         * <p>
         * This must be called from a UI thread. To call from a non-UI thread, call
         * {@link #postInvalidate()}.
         */
        public void invalidate() {
            invalidate(true);
        }
    

    通过invalidate方法的源码注释可以大致知道三点:
    1.调用invalidate方法会刷新ui,前提是该view是可见的;
    2.调用invalidate方法后,onDraw方法也会被调用;
    3.invalidate方法的调用必须在ui线程中,如果在非ui线程中可以使用postInvalidate方法更新ui,这也是invalidate和postInvalidate方法的区别

    调用View中的invalidate方法后,接着会调用View中的invalidateInternal方法,在invalidateInternal方法中会调用skinInvalidate方法判断该view是否可见,该view是否有动画,接着会调用ViewParent中的invalidateChild方法;

    void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
                boolean fullInvalidate) {
            if (mGhostView != null) {
                mGhostView.invalidate(true);
                return;
            }
    //调用skinInvalidate方法判断该view是否可见,是否有动画,
    //如果该view是不可见的,并且是没有动画的就是返回,不进行更新
            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;
    //将mParent赋值给ViewParent对象
                final ViewParent p = mParent;
                if (p != null && ai != null && l < r && t < b) {
                    final Rect damage = ai.mTmpInvalRect;
                    damage.set(l, t, r, b);
    //调用ViewParent中的invalidateChild方法
                    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();
                    }
                }
    
                // Damage the entire IsolatedZVolume receiving this view's shadow.
                if (isHardwareAccelerated() && getZ() != 0) {
                    damageShadowReceiver();
                }
            }
        }
    

    现在就到了ViewParent中的invalidateChild方法,会发现ViewParent是一个接口,就需要去找它的实现类,ViewGroup和ViewRootImpl都是它的实现类,所以就找ViewGroup中的invalidateChild方法;

        @Override
        public final void invalidateChild(View child, final Rect dirty) {
    //将当前ViewGroup赋值给ViewParent,
    //这样ViewParent就不会为null,在下面的whlie循环中就可以进行循环
            ViewParent parent = this;
    
            final AttachInfo attachInfo = mAttachInfo;
            if (attachInfo != null) {
                // If the child is drawing an animation, we want to copy this flag onto
                // ourselves and the parent to make sure the invalidate request goes
                // through
                final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION)
                        == PFLAG_DRAW_ANIMATION;
    
                // Check whether the child that requests the invalidate is fully opaque
                // Views being animated or transformed are not considered opaque because we may
                // be invalidating their old position and need the parent to paint behind them.
                Matrix childMatrix = child.getMatrix();
                final boolean isOpaque = child.isOpaque() && !drawAnimation &&
                        child.getAnimation() == null && childMatrix.isIdentity();
                // Mark the child as dirty, using the appropriate flag
                // Make sure we do not set both flags at the same time
                int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
    
                if (child.mLayerType != LAYER_TYPE_NONE) {
                    mPrivateFlags |= PFLAG_INVALIDATED;
                    mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
                }
    
                final int[] location = attachInfo.mInvalidateChildLocation;
                location[CHILD_LEFT_INDEX] = child.mLeft;
                location[CHILD_TOP_INDEX] = child.mTop;
                if (!childMatrix.isIdentity() ||
                        (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
                    RectF boundingRect = attachInfo.mTmpTransformRect;
                    boundingRect.set(dirty);
                    Matrix transformMatrix;
                    if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
                        Transformation t = attachInfo.mTmpTransformation;
                        boolean transformed = getChildStaticTransformation(child, t);
                        if (transformed) {
                            transformMatrix = attachInfo.mTmpMatrix;
                            transformMatrix.set(t.getMatrix());
                            if (!childMatrix.isIdentity()) {
                                transformMatrix.preConcat(childMatrix);
                            }
                        } else {
                            transformMatrix = childMatrix;
                        }
                    } else {
                        transformMatrix = childMatrix;
                    }
                    transformMatrix.mapRect(boundingRect);
                    dirty.set((int) Math.floor(boundingRect.left),
                            (int) Math.floor(boundingRect.top),
                            (int) Math.ceil(boundingRect.right),
                            (int) Math.ceil(boundingRect.bottom));
                }
    //进行while循环
                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;
                        }
                    }
    
                    // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
                    // flag coming from the child that initiated the invalidate
                    if (view != null) {
                        if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
                                view.getSolidColor() == 0) {
                            opaqueFlag = PFLAG_DIRTY;
                        }
                        if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
                            view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;
                        }
                    }
    //这里会不停的调用ViewParent中的invalidateChildInParent方法,
    //并返回一个ViewParent对象,会一直往外遍历,知道最外层ViewRootImpl,
    //返回的ViewParent对象为null就跳出该循环
                    parent = parent.invalidateChildInParent(location, dirty);
                    if (view != null) {
                        // Account for transform on current parent
                        Matrix m = view.getMatrix();
                        if (!m.isIdentity()) {
                            RectF boundingRect = attachInfo.mTmpTransformRect;
                            boundingRect.set(dirty);
                            m.mapRect(boundingRect);
                            dirty.set((int) Math.floor(boundingRect.left),
                                    (int) Math.floor(boundingRect.top),
                                    (int) Math.ceil(boundingRect.right),
                                    (int) Math.ceil(boundingRect.bottom));
                        }
                    }
                } while (parent != null);
            }
        }
    

    invalidateChild是不能被重写的,在该方法中的while循环中会不听的调用ViewParent中的invalidateChildInParent方法,并返回一个ViewParent对象,会一直往外层遍历,直到ViewRootImpl中的invalidateChildInParent方法,如果返回ViewParent为null就跳出当前循环;
    遍历到最外层后就会去调动ViewRootImpl中的invalidateChildInParent方法;

    @Override
        public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
    //调用checkThread去检测当前线程是不是ui线程,如果不是就会抛异常
            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方法去更新绘制ui
            invalidateRectOnScreen(dirty);
    
            return null;
        }
    

    在ViewRootImpl的invalidateChildInParent方法中首先会调用checkThread方法去检测当前线程是否是ui线程,如果不是ui线程,就会抛异常,这也是不能在非ui线程更新ui的原因;接着就会调用invalidateRectOnScreen方法;在invalidateRectOnScreen方法中就会去调用scheduleTraversals方法;在scheduleTraversals方法中就会调用postCallBack并传入一个TraversalRunnable对象;在TraversalRunnable对象的run方法中会去调用doTraversal方法;

    void doTraversal() {
            if (mTraversalScheduled) {
                mTraversalScheduled = false;
                mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
    
                if (mProfile) {
                    Debug.startMethodTracing("ViewAncestor");
                }
    //调用performTraversals方法进行绘制准备工作;
                performTraversals();
    
                if (mProfile) {
                    Debug.stopMethodTracing();
                    mProfile = false;
                }
            }
        }
    

    在performTraversals方法中就会去调用performMearsure、performLayout、performDraw等方法,不过在invalidate刷新ui的时候只会调用performDraw方法,所有只去看performDraw方法就可以了;在performDraw中就会去调用draw方法;在draw中就会去调用drawSofeware方法;

    **
         * @return true if drawing was successful, false if an error occurred
         */
        private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
                boolean scalingRequired, Rect dirty) {
    
            // Draw with software renderer.
    //定义一个Canvas画布
            final Canvas canvas;
            try {
                final int left = dirty.left;
                final int top = dirty.top;
                final int right = dirty.right;
                final int bottom = dirty.bottom;
    
                canvas = mSurface.lockCanvas(dirty);
    
                // The dirty rectangle can be modified by Surface.lockCanvas()
                //noinspection ConstantConditions
                if (left != dirty.left || top != dirty.top || right != dirty.right
                        || bottom != dirty.bottom) {
                    attachInfo.mIgnoreDirtyState = true;
                }
    
                // TODO: Do this in native
                canvas.setDensity(mDensity);
            } catch (Surface.OutOfResourcesException e) {
                handleOutOfResourcesException(e);
                return false;
            } catch (IllegalArgumentException e) {
                Log.e(mTag, "Could not lock surface", e);
                // Don't assume this is due to out of memory, it could be
                // something else, and if it is something else then we could
                // kill stuff (or ourself) for no reason.
                mLayoutRequested = true;    // ask wm for a new surface next time.
                return false;
            }
    
            try {
                if (DEBUG_ORIENTATION || DEBUG_DRAW) {
                    Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
                            + canvas.getWidth() + ", h=" + canvas.getHeight());
                    //canvas.drawARGB(255, 255, 0, 0);
                }
    
                // If this bitmap's format includes an alpha channel, we
                // need to clear it before drawing so that the child will
                // properly re-composite its drawing on a transparent
                // background. This automatically respects the clip/dirty region
                // or
                // If we are applying an offset, we need to clear the area
                // where the offset doesn't appear to avoid having garbage
                // left in the blank areas.
                if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
                    canvas.drawColor(0, PorterDuff.Mode.CLEAR);
                }
    
                dirty.setEmpty();
                mIsAnimating = false;
                mView.mPrivateFlags |= View.PFLAG_DRAWN;
    
                if (DEBUG_DRAW) {
                    Context cxt = mView.getContext();
                    Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
                            ", metrics=" + cxt.getResources().getDisplayMetrics() +
                            ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
                }
                try {
                    canvas.translate(-xoff, -yoff);
                    if (mTranslator != null) {
                        mTranslator.translateCanvas(canvas);
                    }
                    canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
                    attachInfo.mSetIgnoreDirtyState = false;
    //调用view中的draw方法,并将定义的canvas画布传入
                    mView.draw(canvas);
    
                    drawAccessibilityFocusedDrawableIfNeeded(canvas);
                } finally {
                    if (!attachInfo.mSetIgnoreDirtyState) {
                        // Only clear the flag if it was not set during the mView.draw() call
                        attachInfo.mIgnoreDirtyState = false;
                    }
                }
            } finally {
                try {
                    surface.unlockCanvasAndPost(canvas);
                } catch (IllegalArgumentException e) {
                    Log.e(mTag, "Could not unlock surface", e);
                    mLayoutRequested = true;    // ask wm for a new surface next time.
                    //noinspection ReturnInsideFinallyBlock
                    return false;
                }
    
                if (LOCAL_LOGV) {
                    Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
                }
            }
            return true;
        }
    

    终于到了View中的draw方法了;

    @CallSuper
        public void draw(Canvas canvas) {
            final int privateFlags = mPrivateFlags;
    //定义dirtyOpaque 标识,用来控制drawBackground onDraw等方法的调用
            final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
                    (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
            mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
    
            /*
             * Draw traversal performs several drawing steps which must be executed
             * in the appropriate order:
             *
             *      1. Draw the background    绘制背景
             *      2. If necessary, save the canvas' layers to prepare for fading
             *      3. Draw view's content    绘制内容
             *      4. Draw children   绘制子view
             *      5. If necessary, draw the fading edges and restore layers
             *      6. Draw decorations (scrollbars for instance)
             */
    
            // Step 1, draw the background, if needed
            int saveCount;
    
            if (!dirtyOpaque) {
    //没有设置背景,默认的ViewGroup不会调用该方法
                drawBackground(canvas);
            }
    
            // skip step 2 & 5 if possible (common case)
            final int viewFlags = mViewFlags;
            boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
            boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
            if (!verticalEdges && !horizontalEdges) {
                // Step 3, draw the content  默认的ViewGroup不会调用该方法
                if (!dirtyOpaque) onDraw(canvas);
    
                // Step 4, draw the children
                dispatchDraw(canvas);
    
                // Overlay is part of the content and draws beneath Foreground
                if (mOverlay != null && !mOverlay.isEmpty()) {
                    mOverlay.getOverlayView().dispatchDraw(canvas);
                }
    
                // Step 6, draw decorations (foreground, scrollbars)
                onDrawForeground(canvas);
    
                // we're done...
                return;
            }
    
            /*
             * Here we do the full fledged routine...
             * (this is an uncommon case where speed matters less,
             * this is why we repeat some of the tests that have been
             * done above)
             */
    
            boolean drawTop = false;
            boolean drawBottom = false;
            boolean drawLeft = false;
            boolean drawRight = false;
    
            float topFadeStrength = 0.0f;
            float bottomFadeStrength = 0.0f;
            float leftFadeStrength = 0.0f;
            float rightFadeStrength = 0.0f;
    
            // Step 2, save the canvas' layers
            int paddingLeft = mPaddingLeft;
    
            final boolean offsetRequired = isPaddingOffsetRequired();
            if (offsetRequired) {
                paddingLeft += getLeftPaddingOffset();
            }
    
            int left = mScrollX + paddingLeft;
            int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
            int top = mScrollY + getFadeTop(offsetRequired);
            int bottom = top + getFadeHeight(offsetRequired);
    
            if (offsetRequired) {
                right += getRightPaddingOffset();
                bottom += getBottomPaddingOffset();
            }
    
            final ScrollabilityCache scrollabilityCache = mScrollCache;
            final float fadeHeight = scrollabilityCache.fadingEdgeLength;
            int length = (int) fadeHeight;
    
            // clip the fade length if top and bottom fades overlap
            // overlapping fades produce odd-looking artifacts
            if (verticalEdges && (top + length > bottom - length)) {
                length = (bottom - top) / 2;
            }
    
            // also clip horizontal fades if necessary
            if (horizontalEdges && (left + length > right - length)) {
                length = (right - left) / 2;
            }
    
            if (verticalEdges) {
                topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength()));
                drawTop = topFadeStrength * fadeHeight > 1.0f;
                bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength()));
                drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
            }
    
            if (horizontalEdges) {
                leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength()));
                drawLeft = leftFadeStrength * fadeHeight > 1.0f;
                rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength()));
                drawRight = rightFadeStrength * fadeHeight > 1.0f;
            }
    
            saveCount = canvas.getSaveCount();
    
            int solidColor = getSolidColor();
            if (solidColor == 0) {
                final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
    
                if (drawTop) {
                    canvas.saveLayer(left, top, right, top + length, null, flags);
                }
    
                if (drawBottom) {
                    canvas.saveLayer(left, bottom - length, right, bottom, null, flags);
                }
    
                if (drawLeft) {
                    canvas.saveLayer(left, top, left + length, bottom, null, flags);
                }
    
                if (drawRight) {
                    canvas.saveLayer(right - length, top, right, bottom, null, flags);
                }
            } else {
                scrollabilityCache.setFadeColor(solidColor);
            }
    
            // Step 3, draw the content
            if (!dirtyOpaque) onDraw(canvas);
    
            // Step 4, draw the children
            dispatchDraw(canvas);
    
            // Step 5, draw the fade effect and restore layers
            final Paint p = scrollabilityCache.paint;
            final Matrix matrix = scrollabilityCache.matrix;
            final Shader fade = scrollabilityCache.shader;
    
            if (drawTop) {
                matrix.setScale(1, fadeHeight * topFadeStrength);
                matrix.postTranslate(left, top);
                fade.setLocalMatrix(matrix);
                p.setShader(fade);
                canvas.drawRect(left, top, right, top + length, p);
            }
    
            if (drawBottom) {
                matrix.setScale(1, fadeHeight * bottomFadeStrength);
                matrix.postRotate(180);
                matrix.postTranslate(left, bottom);
                fade.setLocalMatrix(matrix);
                p.setShader(fade);
                canvas.drawRect(left, bottom - length, right, bottom, p);
            }
    
            if (drawLeft) {
                matrix.setScale(1, fadeHeight * leftFadeStrength);
                matrix.postRotate(-90);
                matrix.postTranslate(left, top);
                fade.setLocalMatrix(matrix);
                p.setShader(fade);
                canvas.drawRect(left, top, left + length, bottom, p);
            }
    
            if (drawRight) {
                matrix.setScale(1, fadeHeight * rightFadeStrength);
                matrix.postRotate(90);
                matrix.postTranslate(right, top);
                fade.setLocalMatrix(matrix);
                p.setShader(fade);
                canvas.drawRect(right - length, top, right, bottom, p);
            }
    
            canvas.restoreToCount(saveCount);
    
            // Overlay is part of the content and draws beneath Foreground
            if (mOverlay != null && !mOverlay.isEmpty()) {
                mOverlay.getOverlayView().dispatchDraw(canvas);
            }
    
            // Step 6, draw decorations (foreground, scrollbars)
            onDrawForeground(canvas);
        }
    

    最终会去调用View中的onDraw方法,然后在自定定义view中重写onDraw方法,进行ui刷新和绘制,在View的draw方法中绘制工作分为以下:
    1.调用drawBackground方法绘制背景
    2.调用onDraw方法绘制内容
    3.调用dispatchDraw方法绘制子view
    4.调用onDrawForeground绘制装饰
    这些方法中默认的ViewGroup不会走drawBackground和onDraw方法,在继承自ViewGroup的自定义view中要绘制的话,可以重写onDraw方法,并设置背景,或者重写dispatchDraw方法,在里面进行绘制,方法有很多;
    上面大致就是对invalidate的源码分析,接下来看postInvalidate方法;

    postInvalidate

    /**
         * <p>Cause an invalidate to happen on a subsequent cycle through the event loop.
         * Use this to invalidate the View from a non-UI thread.</p>
         *
         * <p>This method can be invoked from outside of the UI thread
         * only when this View is attached to a window.</p>
         *
         * @see #invalidate()
         * @see #postInvalidateDelayed(long)
         */
        public void postInvalidate() {
            postInvalidateDelayed(0);
        }
    

    通过源码注释很明显该方法被调用于ui线程以外去更新绘制ui;接着会去调用postInvalidateDelayed方法;

     public void postInvalidateDelayed(long delayMilliseconds) {
            // We try only with the AttachInfo because there's no point in invalidating
            // if we are not attached to our window
            final AttachInfo attachInfo = mAttachInfo;
            if (attachInfo != null) {
                attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds);
            }
        }
    

    在postInvalidateDelayed方法中就直接去调用ViewRootImpl中的dispatchInvalidateDelayed方法;

    public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
    //实例化一个Message消息对象
            Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
    //发送消息
            mHandler.sendMessageDelayed(msg, delayMilliseconds);
        }
    

    在dispatchInvalidateDelayed方法中会通过handler实例化一个Message对象,然后通过handler发送消息;这里的hanlder是ViewRootHandler,在ViewRootHandler的handleMessage方法中就会根据消息标识进行处理;

    final class ViewRootHandler extends Handler {
            @Override
            public String getMessageName(Message message) {
                ......
                return super.getMessageName(message);
            }
    
            @Override
            public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
                if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) {
                    // Debugging for b/27963013
                    throw new NullPointerException(
                            "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:");
                }
                return super.sendMessageAtTime(msg, uptimeMillis);
            }
    
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
    //根据消息标识来进行处理
                case MSG_INVALIDATE:
    //调用view中invalidate方法
                    ((View) msg.obj).invalidate();
                    break;
                ......
                }
            }
        }
    

    走到这里会看到postInvalidate最终还是通过调用view中的invaidate方法进行view绘制更新,后面流程可以看上面invalidate的绘制流程。

    结论

    invalidate是在ui线程中使用,postInvalidate是在非ui线程中使用,postInvalidate通过ViewRootHandler消息切换到主线程中,最终还是通过调用View中的invalidate方法进行ui的绘制更新,不管是invalidate还是postInvalidate只有当该View为可见时才会进行view的更新绘制,调用invalidate或者postInvalidate更新绘制view时,只会调用onDraw方法,不会调用onMeasure和onLayout方法。

    相关文章

      网友评论

          本文标题:invalidate和postInvalidate使用场景及源码

          本文链接:https://www.haomeiwen.com/subject/qjcvcqtx.html