invalidate与postinvalidate的区别

  • 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()执行重绘操作
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值