美文网首页
invalidate()/postInvalidate()/po

invalidate()/postInvalidate()/po

作者: 星空下奔跑 | 来源:发表于2019-03-24 20:21 被阅读0次

    1、invalidate()

    #View.java
    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) {
               ...
               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);
                   //ViewParent
                   p.invalidateChild(this, damage);
               }
               ...
           }
       }
    
    #ViewRootImpl.java
    public void invalidateChild(View child, Rect dirty) {
           invalidateChildInParent(null, dirty);
       }
    
    public ViewParent invalidateChildInParent(int[] location, Rect dirty) { 
           checkThread();
           ...
           invalidateRectOnScreen(dirty);
           return null;
       }
    
    
    private void invalidateRectOnScreen(Rect dirty) {
           ...
           if (!mWillDrawSoon && (intersected || mIsAnimating)) {
               scheduleTraversals();
           }
       }
    
    void scheduleTraversals() {
           if (!mTraversalScheduled) {
               mTraversalScheduled = true;
               mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
               mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable,null);
               if (!mUnbufferedInputDispatch) {
                   scheduleConsumeBatchedInput();
               }
               notifyRendererOfFramePending();
               pokeDrawLockIfNeeded();
           }
       }
    

    可以看到invalidate()的调用顺序为:

    View.invalidate()->View.invalidateInternal()->ViewRootImpl.invalidateChild()->
    ViewRoottImpl.invalidateChildInParent()->ViewRootImpl.invalidateRectOnScreen()->
    ViewRootImpl.scheduleTraversals()
    

    2、postInvalidate()

    #View.java
    public void postInvalidate() {
            postInvalidateDelayed(0);
        }
    
    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);
            }
        }
    #ViewRootImpl.java
     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 void handleMessage(Message msg) {
                switch (msg.what) {
                      case MSG_INVALIDATE:
                        ((View) msg.obj).invalidate();
                        break;
                    case MSG_INVALIDATE_RECT:
                        final View.AttachInfo.InvalidateInfo info =
                                (View.AttachInfo.InvalidateInfo) msg.obj;
                        info.target.invalidate(info.left, info.top, info.right, info.bottom);
                        info.recycle();
                        break;
                    ...
               }
    ...
    }
    

    可以看到postInvalidate()调用顺序为:

    View.postInvalidate()->View.postInvalidateDelayed()->ViewRootImpl.dispatchInvalidateDelayed()->
    handleMessage(MSG_INVALIDATE/MSG_INVALIDATE_RECT)->View.invalidate()
    

    所以invalidate()和postinvalidate()的区别就是
    postinvalidate()官方的注释:

    • Cause an invalidate of the specified area to happen on a subsequent cycle through the event loop. Use this to invalidate the View from a non-UI thread.
      可以在非UI线程刷新UI。

    3、postInvalidateOnAnimation()

    #ViewCompat.java
    public static void postInvalidateOnAnimation(@NonNull View view) {
            //SDK版本
            if (Build.VERSION.SDK_INT >= 16) {
                view.postInvalidateOnAnimation();
            } else {
                view.postInvalidate();
            }
        }
    
    public void postInvalidateOnAnimation() {
            // 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.dispatchInvalidateOnAnimation(this);
            }
        }
    
    public void dispatchInvalidateOnAnimation(View view) {
            mInvalidateOnAnimationRunnable.addView(view);
        }
    
    final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
                new InvalidateOnAnimationRunnable();
    final class InvalidateOnAnimationRunnable implements Runnable {
            private boolean mPosted;
            private final ArrayList<View> mViews = new ArrayList<View>();
            private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
                    new ArrayList<AttachInfo.InvalidateInfo>();
            private View[] mTempViews;
            private AttachInfo.InvalidateInfo[] mTempViewRects;
    
            public void addView(View view) {
                synchronized (this) {
                    mViews.add(view);
                    postIfNeededLocked();
                }
            }
            public void removeView(View view) {
                synchronized (this) {
                    mViews.remove(view);
                    ...
                    if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
                      mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
                        mPosted = false;
                    }
                }
            }
    
            @Override
            public void run() {
                final int viewCount;
                final int viewRectCount;
                synchronized (this) {
                ...
                for (int i = 0; i < viewCount; i++) {
                    mTempViews[i].invalidate();
                    mTempViews[i] = null;
                }
    
                for (int i = 0; i < viewRectCount; i++) {
                    final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
                    info.target.invalidate(info.left, info.top, info.right, info.bottom);
                    info.recycle();
                }
            }
    
            private void postIfNeededLocked() {
                if (!mPosted) {
                    mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
                    mPosted = true;
                }
            }
        }
    

    postInvalidateOnAnimation()调用顺序为:

    View.postInvalidateOnAnimation()->ViewRootImpl.dispatchInvalidateOnAnimation()->
    InvalidateOnAnimationRunnable.postIfNeededLocked()->
    Choreographer.CALLBACK_ANIMATION->View.invalidate()
    

    总结

    invalidate()会立即调用scheduleTraversals().
    postinvalidate()会通过消息机制调用invalidate()最终调用scheduleTraversals().
    postInvalidateOnAnimation()会通过Vsync机制插入到Choreographer的ANIMATION队列,下次屏幕刷新信号到来时调用invalidate()然后scheduleTraversals()。这个方法也可以在非UI线程调用。

    相关文章

      网友评论

          本文标题:invalidate()/postInvalidate()/po

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