<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      安卓筆記俠

      專(zhuān)注安卓開(kāi)發(fā)

      導(dǎo)航

      Android視圖重繪,使用invalidate還是requestLayout

      概述

      在我們?cè)谶M(jìn)行自定義View的相關(guān)開(kāi)發(fā)中,當(dāng)我們更改了當(dāng)前View的狀態(tài),比如大小,位置等,我們需要重新刷新整個(gè)界面,保證顯示最新的狀態(tài)。在Android中,讓當(dāng)前的視圖重繪有兩種方式,invalidate和requestLayout,今天我們看看這兩種方式的原理以及區(qū)別。

      分析

      invalidate的原理

      public void invalidate() {
              invalidate(true);
      }

      最后會(huì)調(diào)用到invalidateInternal這個(gè)方法

       1 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
       2             boolean fullInvalidate) {
       3         if (mGhostView != null) {
       4             mGhostView.invalidate(true);
       5             return;
       6         }
       7 
       8         if (skipInvalidate()) {
       9             return;
      10         }
      11 
      12         if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
      13                 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)
      14                 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED
      15                 || (fullInvalidate && isOpaque() != mLastIsOpaque)) {
      16             if (fullInvalidate) {
      17                 mLastIsOpaque = isOpaque();
      18                 mPrivateFlags &= ~PFLAG_DRAWN;
      19             }
      20 
      21             mPrivateFlags |= PFLAG_DIRTY;
      22 
      23             if (invalidateCache) {
      24                 mPrivateFlags |= PFLAG_INVALIDATED;
      25                 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
      26             }
      27 
      28             // Propagate the damage rectangle to the parent view.
      29             final AttachInfo ai = mAttachInfo;
      30             final ViewParent p = mParent;
      31             if (p != null && ai != null && l < r && t < b) {
      32                 final Rect damage = ai.mTmpInvalRect;
      33                 damage.set(l, t, r, b);
      34                 p.invalidateChild(this, damage);
      35             }
      36             .....

      我們看到方法的最后調(diào)用了ViewParent的invalidateChild方法,因?yàn)閂iewParent是個(gè)接口,invalidateChild是空實(shí)現(xiàn),我們?nèi)タ纯此膶?shí)現(xiàn)類(lèi)ViewRootImpl中的invalidateChild是如何做的

       @Override
          public void invalidateChild(View child, Rect dirty) {
              invalidateChildInParent(null, dirty);
          }

       

       1  @Override
       2     public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
       3         checkThread();
       4         if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
       5 
       6         if (dirty == null) {
       7             invalidate();
       8             return null;
       9         } else if (dirty.isEmpty() && !mIsAnimating) {
      10             return null;
      11         }
      12 
      13         if (mCurScrollY != 0 || mTranslator != null) {
      14             mTempRect.set(dirty);
      15             dirty = mTempRect;
      16             if (mCurScrollY != 0) {
      17                 dirty.offset(0, -mCurScrollY);
      18             }
      19             if (mTranslator != null) {
      20                 mTranslator.translateRectInAppWindowToScreen(dirty);
      21             }
      22             if (mAttachInfo.mScalingRequired) {
      23                 dirty.inset(-1, -1);
      24             }
      25         }
      26 
      27         invalidateRectOnScreen(dirty);
      28 
      29         return null;
      30     }

      又會(huì)調(diào)用ViewRootImpl中的invalidate方法

      void invalidate() {
              mDirty.set(0, 0, mWidth, mHeight);
              if (!mWillDrawSoon) {
                  scheduleTraversals();
              }
          }

      這里調(diào)用了scheduleTraversals重新開(kāi)始了View的繪制,我們知道View的繪制是從ViewRootImpl的performTraversals方法開(kāi)始的。我們看看scheduleTraversals是不是觸發(fā)了performTraversals。

      void scheduleTraversals() {
              if (!mTraversalScheduled) {
                  mTraversalScheduled = true;
                  mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
                  mChoreographer.postCallback(
                          Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
                  if (!mUnbufferedInputDispatch) {
                      scheduleConsumeBatchedInput();
                  }
                  notifyRendererOfFramePending();
                  pokeDrawLockIfNeeded();
              }
          }

      在scheduleTraversals方法中我們發(fā)現(xiàn)了一個(gè)mTraversalRunnable對(duì)象,這個(gè)對(duì)象就是我們要觀察的重點(diǎn)

      final class TraversalRunnable implements Runnable {
              @Override
              public void run() {
                  doTraversal();
              }
          }
          final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

      我們發(fā)現(xiàn)這個(gè)對(duì)象就是一個(gè)Runnable對(duì)象,我們?cè)趕cheduleTraversals方法中傳入mTraversalRunnable 就會(huì)執(zhí)行run方法,其中又調(diào)用了doTraversal這個(gè)方法

       void doTraversal() {
              if (mTraversalScheduled) {
                  mTraversalScheduled = false;
                  mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
      
                  if (mProfile) {
                      Debug.startMethodTracing("ViewAncestor");
                  }
      
                  performTraversals();
      
                  if (mProfile) {
                      Debug.stopMethodTracing();
                      mProfile = false;
                  }
              }
          }

      最后我們發(fā)現(xiàn)在doTraversal方法中調(diào)用了performTraversals開(kāi)始了View的重新繪制,這就是invalidate的整個(gè)過(guò)程。

      requestLayout的原理

      public void requestLayout() {
              if (mMeasureCache != null) mMeasureCache.clear();
      
              if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {
                  // Only trigger request-during-layout logic if this is the view requesting it,
                  // not the views in its parent hierarchy
                  ViewRootImpl viewRoot = getViewRootImpl();
                  if (viewRoot != null && viewRoot.isInLayout()) {
                      if (!viewRoot.requestLayoutDuringLayout(this)) {
                          return;
                      }
                  }
                  mAttachInfo.mViewRequestingLayout = this;
              }
      
              mPrivateFlags |= PFLAG_FORCE_LAYOUT;
              mPrivateFlags |= PFLAG_INVALIDATED;
      
              if (mParent != null && !mParent.isLayoutRequested()) {
                  mParent.requestLayout();
              }
              if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {
                  mAttachInfo.mViewRequestingLayout = null;
              }
          }

      其中會(huì)調(diào)用ViewParent的requestLayout方法,同樣,我們?nèi)タ碫iewRootImpl中的requestLayout方法。

      Override
          public void requestLayout() {
              if (!mHandlingLayoutInLayoutRequest) {
                  checkThread();
                  mLayoutRequested = true;
                  scheduleTraversals();
              }
          }

      這里調(diào)用了scheduleTraversals,后面的步驟就和上面invalidate時(shí)一樣了。相對(duì)來(lái)說(shuō),requestLayout的流程還是比較簡(jiǎn)單的。

      區(qū)別

      既然兩種方式都可以完成View的重繪,那么有什么區(qū)別呢? 
      使用invalidate重繪當(dāng)前視圖是不會(huì)再次執(zhí)行measure和layout流程的。因?yàn)橐晥D沒(méi)有強(qiáng)制重新測(cè)量的標(biāo)志位,而且大小也沒(méi)有發(fā)生過(guò)變化,所以這時(shí)只有draw流程可以得到執(zhí)行。 
      如果你希望視圖的繪制流程可以完完整整地重新走一遍,就不能使用invalidate()方法,而應(yīng)該調(diào)用requestLayout()了

       

      posted on 2018-04-12 15:15  安卓筆記俠  閱讀(3889)  評(píng)論(0)    收藏  舉報(bào)

      主站蜘蛛池模板: 鲁丝片一区二区三区免费| 不卡国产一区二区三区| 一本一本久久aa综合精品| 亚洲婷婷综合色高清在线| 午夜通通国产精品福利| 久久精品国产精品亚洲综合| 99久久精品国产一区二区| AV区无码字幕中文色| 少妇高潮惨叫喷水在线观看| 2020国产欧洲精品网站| 久久综合伊人77777| 国产激情福利短视频在线| 91在线视频视频在线| 乱色熟女综合一区二区三区| 日韩人妻少妇一区二区三区| 国产精品国产精品偷麻豆| 亚洲精品一区二区毛豆| 在线观看AV永久免费| 亚洲欧洲美洲无码精品va| 爱色精品视频一区二区| 欧美做受视频播放| 国产对白老熟女正在播放| 曰本丰满熟妇xxxx性| 亚洲av色香蕉一区二区| 国产精品日韩中文字幕| 狠狠色噜噜狠狠狠狠色综合久| 国产对白老熟女正在播放| 精品人妻蜜臀一区二区三区| 色99久久久久高潮综合影院 | 日韩人妻无码精品专区综合网| 在线中文一区字幕对白| 免费特黄夫妻生活片| 国产精品午夜精品福利| 国产乱人伦真实精品视频| 唐人社视频呦一区二区| 色婷婷综合久久久中文字幕 | 丰满熟妇人妻中文字幕| 国内自拍视频在线一区| 亚洲男人天堂东京热加勒比| 日本中文字幕久久网站| 婷婷丁香五月激情综合|