postInvalidate和invalidate的区别

区别

  • 相同点:都是用来更新当前的View
  • 不同点:invalide实在UI线程中刷新View,要想在非UI线程中刷新View,就要用postInvalidate,因为postInvalidate底层是使用了Handler
  • Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。
  • invalide要在主线程调用,postInvalidate哪里都可以调用
  • Invalidate调用onDraw方法,requestLayout调用onMeasure和onLayout,不一定调用onDraw
  • invalidate()的调用是把之前的旧的view从主UI线程队列中pop掉
  • invalidate()得在UI线程中被调动,在工作者线程中可以通过Handler来通知UI线程进行界面更新。而postInvalidate()在工作者线程中被调用

使用情景

  • 利用invalidate()刷新界面
    实例化一个Handler对象,并重写handleMessage方法调用invalidate()实现界面刷新;而在线程中通过sendMessage发送界面更新消息。
new Thread(new GameThread()).start();
  
  // 实例化一个handler 
 Handler myHandler = new Handler() {
 // 接收到消息后处理
 public void handleMessage(Message msg) {
     switch (msg.what) {
         case Activity01.REFRESH:
         mGameView.invalidate(); // 刷新界面
         break;
     }
     super.handleMessage(msg);
     }
 }; 
 
 class GameThread implements Runnable {
     public void run() {
         while (!Thread.currentThread().isInterrupted()) {
             Message message = new Message();
             message.what = Activity01.REFRESH;
             // 发送消息          
             Activity01.this.myHandler.sendMessage(message);
             try {
             Thread.sleep(100);
             } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
             }
         }
     }
 }
  • 使用postInvalidate()刷新界面
    使用postInvalidate则比较简单,不需要handler,直接在线程中调用postInvalidate即可。
使用postInvalidate则比较简单,不需要handler,直接在工作线程中调用postInvalidate即可。  
 
  class GameThread implements Runnable {
      public void run() {
          while (!Thread.currentThread().isInterrupted()) {
          try {
              Thread.sleep(100);
          } catch (InterruptedException e) {
          Thread.currentThread().interrupt();
         }
 
         // 使用postInvalidate可以直接在工作线程中更新界面
         mGameView.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);
    }
/**
     * <p>Cause an invalidate to happen on a subsequent cycle through the event
     * loop. Waits for the specified amount of time.</p>
     *
     * <p>This method can be invoked from outside of the UI thread
     * only when this View is attached to a window.</p>
     *
     * @param delayMilliseconds the duration in milliseconds to delay the
     *         invalidation by
     *
     * @see #invalidate()
     * @see #postInvalidate()
     */
    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);
        }
    }
 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
        Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
        mHandler.sendMessageDelayed(msg, delayMilliseconds);
    }
  • requestLayout

当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求parent view(父类的视图)重新调用他的onMeasure onLayout来重新设置自己位置。特别是当view的layoutparameter发生改变,并且它的值还没能应用到view上时,这时候适合调用这个方法

调用invalidate时,它会检查上一次请求的UI重绘是否完成,如果没有完成的话,那么它就什么都不做。

void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
            boolean fullInvalidate) {
            .....
         //DRAWN和HAS_BOUNDS是否被设置为1,说明上一次请求执行的UI绘制已经完成,那么可以再次请求执行
        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)) {
                 ......
                 final AttachInfo ai = mAttachInfo;
                final ViewParent p = mParent;
                final Rect damage = ai.mTmpInvalRect;
                damage.set(l, t, r, b);
                p.invalidateChild(this, damage);//TODO:这是invalidate执行的主体
                .....
        }
    }

而postInvalidate则不会这样,它是向主线程发送个Message,然后handleMessage时,调用了invalidate()函数。

invalidate、postInvalidate与requestLayout浅析
简单讲下postInvalidate与invalidate的区别

发布了10 篇原创文章 · 获赞 1 · 访问量 500

猜你喜欢

转载自blog.csdn.net/qq_34681580/article/details/104756000