王学岗高级UI(2)——UI绘制流程(下)

我们看下ActivityThread这个方法

              @Override
3846      public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
3847              String reason) {
3848          // If we are getting ready to gc after going to the background, well
3849          // we are back active so skip it.
3850          unscheduleGcIdler();
3851          mSomeActivitiesChanged = true;
3852  
3853          // TODO Push resumeArgs into the activity for consideration
3854          final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
3855          if (r == null) {
3856              // We didn't actually resume the activity, so skipping any follow-up actions.
3857              return;
3858          }
3859  
3860          final Activity a = r.activity;
3861  
3862          if (localLOGV) {
3863              Slog.v(TAG, "Resume " + r + " started activity: " + a.mStartedActivity
3864                      + ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished);
3865          }
3866  
3867          final int forwardBit = isForward
3868                  ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
3869  
3870          // If the window hasn't yet been added to the window manager,
3871          // and this guy didn't finish itself or start another activity,
3872          // then go ahead and add the window.
3873          boolean willBeVisible = !a.mStartedActivity;
3874          if (!willBeVisible) {
3875              try {
3876                  willBeVisible = ActivityManager.getService().willActivityBeVisible(
3877                          a.getActivityToken());
3878              } catch (RemoteException e) {
3879                  throw e.rethrowFromSystemServer();
3880              }
3881          }
3882          if (r.window == null && !a.mFinished && willBeVisible) {
3883              r.window = r.activity.getWindow();
3884              View decor = r.window.getDecorView();
3885              decor.setVisibility(View.INVISIBLE);
3886              ViewManager wm = a.getWindowManager();
3887              WindowManager.LayoutParams l = r.window.getAttributes();
3888              a.mDecor = decor;
3889              l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
3890              l.softInputMode |= forwardBit;
3891              if (r.mPreserveWindow) {
3892                  a.mWindowAdded = true;
3893                  r.mPreserveWindow = false;
3894                  // Normally the ViewRoot sets up callbacks with the Activity
3895                  // in addView->ViewRootImpl#setView. If we are instead reusing
3896                  // the decor view we have to notify the view root that the
3897                  // callbacks may have changed.
3898                  ViewRootImpl impl = decor.getViewRootImpl();
3899                  if (impl != null) {
3900                      impl.notifyChildRebuilt();
3901                  }
3902              }
3903              if (a.mVisibleFromClient) {
3904                  if (!a.mWindowAdded) {
3905                      a.mWindowAdded = true;
3906                      wm.addView(decor, l);
3907                  } else {
3908                      // The activity will get a callback for this {@link LayoutParams} change
3909                      // earlier. However, at that time the decor will not be set (this is set
3910                      // in this method), so no action will be taken. This call ensures the
3911                      // callback occurs with the decor set.
3912                      a.onWindowAttributesChanged(l);
3913                  }
3914              }
3915  
3916              // If the window has already been added, but during resume
3917              // we started another activity, then don't yet make the
3918              // window visible.
3919          } else if (!willBeVisible) {
3920              if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
3921              r.hideForNow = true;
3922          }
3923  
3924          // Get rid of anything left hanging around.
3925          cleanUpPendingRemoveWindows(r, false /* force */);
3926  
3927          // The window is now visible if it has been added, we are not
3928          // simply finishing, and we are not starting another activity.
3929          if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
3930              if (r.newConfig != null) {
3931                  performConfigurationChangedForActivity(r, r.newConfig);
3932                  if (DEBUG_CONFIGURATION) {
3933                      Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig "
3934                              + r.activity.mCurrentConfig);
3935                  }
3936                  r.newConfig = null;
3937              }
3938              if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward);
3939              WindowManager.LayoutParams l = r.window.getAttributes();
3940              if ((l.softInputMode
3941                      & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
3942                      != forwardBit) {
3943                  l.softInputMode = (l.softInputMode
3944                          & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
3945                          | forwardBit;
3946                  if (r.activity.mVisibleFromClient) {
3947                      ViewManager wm = a.getWindowManager();
3948                      View decor = r.window.getDecorView();
3949                      wm.updateViewLayout(decor, l);
3950                  }
3951              }
3952  
3953              r.activity.mVisibleFromServer = true;
3954              mNumVisibleActivities++;
3955              if (r.activity.mVisibleFromClient) {
3956                  r.activity.makeVisible();
3957              }
3958          }
3959  
3960          r.nextIdle = mNewActivities;
3961          mNewActivities = r;
3962          if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);
3963          Looper.myQueue().addIdleHandler(new Idler());
3964      }
3965  

这里面有句这样的代码
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);我们跟踪下ActivityThread这句代码,

 @VisibleForTesting
3775      public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
3776              String reason) {
3777          final ActivityClientRecord r = mActivities.get(token);
3778          if (localLOGV) {
3779              Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished);
3780          }
3781          if (r == null || r.activity.mFinished) {
3782              return null;
3783          }
3784          if (r.getLifecycleState() == ON_RESUME) {
3785              if (!finalStateRequest) {
3786                  final RuntimeException e = new IllegalStateException(
3787                          "Trying to resume activity which is already resumed");
3788                  Slog.e(TAG, e.getMessage(), e);
3789                  Slog.e(TAG, r.getStateString());
3790                  // TODO(lifecycler): A double resume request is possible when an activity
3791                  // receives two consequent transactions with relaunch requests and "resumed"
3792                  // final state requests and the second relaunch is omitted. We still try to
3793                  // handle two resume requests for the final state. For cases other than this
3794                  // one, we don't expect it to happen.
3795              }
3796              return null;
3797          }
3798          if (finalStateRequest) {
3799              r.hideForNow = false;
3800              r.activity.mStartedActivity = false;
3801          }
3802          try {
3803              r.activity.onStateNotSaved();
3804              r.activity.mFragments.noteStateNotSaved();
3805              checkAndBlockForNetworkAccess();
3806              if (r.pendingIntents != null) {
3807                  deliverNewIntents(r, r.pendingIntents);
3808                  r.pendingIntents = null;
3809              }
3810              if (r.pendingResults != null) {
3811                  deliverResults(r, r.pendingResults, reason);
3812                  r.pendingResults = null;
3813              }
3814              r.activity.performResume(r.startsNotResumed, reason);
3815  
3816              r.state = null;
3817              r.persistentState = null;
3818              r.setState(ON_RESUME);
3819          } catch (Exception e) {
3820              if (!mInstrumentation.onException(r.activity, e)) {
3821                  throw new RuntimeException("Unable to resume activity "
3822                          + r.intent.getComponent().toShortString() + ": " + e.toString(), e);
3823              }
3824          }
3825          return r;
3826      }
3827  
   if (r.getLifecycleState() == ON_RESUME) {
   }

这句代码就是调用onResume的生命周期。我们在回到handleResumeActivity方法。 final Activity a = r.activity;这句代码是获取当前的Activity。 r.window = r.activity.getWindow();View decor = r.window.getDecorView();通过当前Activity获取window和DecorView。 ViewManager wm = a.getWindowManager();因为WindowManager是一个接口,在这里获取的是WindowManager的实现类WindowManagerImpl,注意ViewManager同样是一个接口,是WindowManager的父类。 wm.addView(decor, l);把decor添加到WindowManagerImpl。我们详细看下WindowManagerImplement类的addView();

  public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
92          applyDefaultToken(params);
93          mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
94      }

这里使用了桥接模式,我们看下mClobal是WindowManagerGlobal 的对象,我们看下WindowManagerGlobal 的addView();

  public void addView(View view, ViewGroup.LayoutParams params,
279              Display display, Window parentWindow) {
280          if (view == null) {
281              throw new IllegalArgumentException("view must not be null");
282          }
283          if (display == null) {
284              throw new IllegalArgumentException("display must not be null");
285          }
286          if (!(params instanceof WindowManager.LayoutParams)) {
287              throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
288          }
289  
290          final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
291          if (parentWindow != null) {
292              parentWindow.adjustLayoutParamsForSubWindow(wparams);
293          } else {
294              // If there's no parent, then hardware acceleration for this view is
295              // set from the application's hardware acceleration setting.
296              final Context context = view.getContext();
297              if (context != null
298                      && (context.getApplicationInfo().flags
299                              & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
300                  wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
301              }
302          }
303  
304          ViewRootImpl root;
305          View panelParentView = null;
306  
307          synchronized (mLock) {
308              // Start watching for system property changes.
309              if (mSystemPropertyUpdater == null) {
310                  mSystemPropertyUpdater = new Runnable() {
311                      @Override public void run() {
312                          synchronized (mLock) {
313                              for (int i = mRoots.size() - 1; i >= 0; --i) {
314                                  mRoots.get(i).loadSystemProperties();
315                              }
316                          }
317                      }
318                  };
319                  SystemProperties.addChangeCallback(mSystemPropertyUpdater);
320              }
321  
322              int index = findViewLocked(view, false);
323              if (index >= 0) {
324                  if (mDyingViews.contains(view)) {
325                      // Don't wait for MSG_DIE to make it's way through root's queue.
326                      mRoots.get(index).doDie();
327                  } else {
328                      throw new IllegalStateException("View " + view
329                              + " has already been added to the window manager.");
330                  }
331                  // The previous removeView() had not completed executing. Now it has.
332              }
333  
334              // If this is a panel window, then find the window it is being
335              // attached to for future reference.
336              if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
337                      wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
338                  final int count = mViews.size();
339                  for (int i = 0; i < count; i++) {
340                      if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
341                          panelParentView = mViews.get(i);
342                      }
343                  }
344              }
345  
346              root = new ViewRootImpl(view.getContext(), display);
347  
348              view.setLayoutParams(wparams);
349  
350              mViews.add(view);
351              mRoots.add(root);
352              mParams.add(wparams);
353  
354              // do this last because it fires off messages to start doing things
355              try {
356                  root.setView(view, wparams, panelParentView);
357              } catch (RuntimeException e) {
358                  // BadTokenException or InvalidDisplayException, clean up.
359                  if (index >= 0) {
360                      removeViewLocked(index, true);
361                  }
362                  throw e;
363              }
364          }
365      }
366  

看下这个类ViewRootImpl,他有四个作用,第一:管理View树;第二,跟WMS通讯,第三,管理Surface,第四,管理事件的分发。
继续往下看下这些代码

                    mViews.add(view);
351              mRoots.add(root);
352              mParams.add(wparams);

集合保存所有Activity的view和root。
继续往下看这句代码,root.setView(view, wparams, panelParentView);这句代码的意思是往root里面添加decorView。root是ViewRootImpl类对象,我们看下该类的setView();

 /**
652      * We have one child
653      */
654     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
655         synchronized (this) {
656             if (mView == null) {
657                 mView = view;//赋值
658 
659           ……
667                 }
668             ……
747                 requestLayout();//遍历View树,请求我们的布局
748         ……
758                     res = mWindowSession.addToDisplay(mWindow, mSeq,  mWindowAttributes,//addToDisplay与WMS进行通讯的。
759                             getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
760                             mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
761                             mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
762                 } catch (RemoteException e) {
763                     mAdded = false;
764                     mView = null;
765                     mAttachInfo.mRootView = null;
766                     mInputChannel = null;
767                     mFallbackEventHandler.setView(null);
768                     unscheduleTraversals();
769                     setAccessibilityFocus(null, null);
770                     throw new RuntimeException("Adding window failed", e);
771                 } finally {
772                     if (restore) {
773                         attrs.restore();
774                     }
775                 }
776 
777                 if (mTranslator != null) {
778                     mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
779                 }
780                 mPendingOverscanInsets.set(0, 0, 0, 0);
781                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
782                 mPendingStableInsets.set(mAttachInfo.mStableInsets);
783                 mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
784                 mPendingVisibleInsets.set(0, 0, 0, 0);
785                 mAttachInfo.mAlwaysConsumeNavBar =
786                         (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
787                 mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
788                 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
789                 if (res < WindowManagerGlobal.ADD_OKAY) {
790                     mAttachInfo.mRootView = null;
791                     mAdded = false;
792                     mFallbackEventHandler.setView(null);
793                     unscheduleTraversals();
794                     setAccessibilityFocus(null, null);
795                     switch (res) {
796                         case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
797                         case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
798                             throw new WindowManager.BadTokenException(
799                                     "Unable to add window -- token " + attrs.token
800                                     + " is not valid; is your activity running?");
801                         case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
802                             throw new WindowManager.BadTokenException(
803                                     "Unable to add window -- token " + attrs.token
804                                     + " is not for an application");
805                         case WindowManagerGlobal.ADD_APP_EXITING:
806                             throw new WindowManager.BadTokenException(
807                                     "Unable to add window -- app for token " + attrs.token
808                                     + " is exiting");
809                         case WindowManagerGlobal.ADD_DUPLICATE_ADD:
810                             throw new WindowManager.BadTokenException(
811                                     "Unable to add window -- window " + mWindow
812                                     + " has already been added");
813                         case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
814                             // Silently ignore -- we would have just removed it
815                             // right away, anyway.
816                             return;
817                         case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
818                             throw new WindowManager.BadTokenException("Unable to add window "
819                                     + mWindow + " -- another window of type "
820                                     + mWindowAttributes.type + " already exists");
821                         case WindowManagerGlobal.ADD_PERMISSION_DENIED:
822                             throw new WindowManager.BadTokenException("Unable to add window "
823                                     + mWindow + " -- permission denied for window type "
824                                     + mWindowAttributes.type);
825                         case WindowManagerGlobal.ADD_INVALID_DISPLAY:
826                             throw new WindowManager.InvalidDisplayException("Unable to add window "
827                                     + mWindow + " -- the specified display can not be found");
828                         case WindowManagerGlobal.ADD_INVALID_TYPE:
829                             throw new WindowManager.InvalidDisplayException("Unable to add window "
830                                     + mWindow + " -- the specified window type "
831                                     + mWindowAttributes.type + " is not valid");
832                     }
833                     throw new RuntimeException(
834                             "Unable to add window -- unknown error code " + res);
835                 }
836 
837                 if (view instanceof RootViewSurfaceTaker) {
838                     mInputQueueCallback =
839                         ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
840                 }
841                 if (mInputChannel != null) {
842                     if (mInputQueueCallback != null) {
843                         mInputQueue = new InputQueue();
844                         mInputQueueCallback.onInputQueueCreated(mInputQueue);
845                     }
846                     mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
847                             Looper.myLooper());
848                 }
849 
850                 view.assignParent(this);
851                 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
852                 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
853 
854                 if (mAccessibilityManager.isEnabled()) {
855                     mAccessibilityInteractionConnectionManager.ensureConnection();
856                 }
857 
858                 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
859                     view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
860                 }
861 
862                 // Set up the input pipeline.
863                 CharSequence counterSuffix = attrs.getTitle();
864                 mSyntheticInputStage = new SyntheticInputStage();
865                 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
866                 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
867                         "aq:native-post-ime:" + counterSuffix);
868                 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
869                 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
870                         "aq:ime:" + counterSuffix);
871                 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
872                 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
873                         "aq:native-pre-ime:" + counterSuffix);
874 
875                 mFirstInputStage = nativePreImeStage;
876                 mFirstPostImeInputStage = earlyPostImeStage;
877                 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
878             }
879         }
880     }
881 
   requestLayout();遍历View树,请求我们的布局。
      res = mWindowSession.addToDisplay(mWindow, mSeq,  mWindowAttributes,
  getHostVisibility(), mDisplay.getDisplayId(), mWinFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,  mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);

mWindowSession是IWindowSession类型的,它是一个Binder对象,用于进行进程间通信,IWindowSession是Client端的代理,它的Server端的实现为Session,此前包含ViewRootImpl在内的代码逻辑都是运行在本地进程的,而Session的addToDisplay方法则运行在WMS所在的进程。说白了就是向系统提供信息,让硬件去渲染。
来看下我们今天的重点 requestLayout();方法。


1222     @Override
1223     public void requestLayout() {
1224         if (!mHandlingLayoutInLayoutRequest) {
1225             checkThread();
1226             mLayoutRequested = true;
1227             scheduleTraversals();
1228         }
1229     }

checkThread();是检查当前线程是否在主线程。我们看下这个方法体,


7757  
7758      void checkThread() {
7759          if (mThread != Thread.currentThread()) {
7760              throw new CalledFromWrongThreadException(
7761                      "Only the original thread that created a view hierarchy can touch its views.");
7762          }
7763      }

这个异常信息大家应该不陌生吧。
scheduleTraversals();就是遍历我们的View树,让我们看下这个方法体。

                 void scheduleTraversals() {
1432         if (!mTraversalScheduled) {
1433             mTraversalScheduled = true;
1434             mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
1435             mChoreographer.postCallback(
1436                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
1437             if (!mUnbufferedInputDispatch) {
1438                 scheduleConsumeBatchedInput();
1439             }
1440             notifyRendererOfFramePending();
1441             pokeDrawLockIfNeeded();
1442         }
1443     }

mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);看下这句代码,其内部实现的原理是使用Handler发送一个消息的。mChoreographer是类 Choreographer 对象,我们跟踪下这个类。我们看下postCallback的调用。

@TestApi
391      public void postCallback(int callbackType, Runnable action, Object token) {
392          postCallbackDelayed(callbackType, action, token, 0);
393      }

继续跟踪postCallbackDelayed方法。

  @TestApi
410      public void postCallbackDelayed(int callbackType,
411              Runnable action, Object token, long delayMillis) {
412          if (action == null) {
413              throw new IllegalArgumentException("action must not be null");
414          }
415          if (callbackType < 0 || callbackType > CALLBACK_LAST) {
416              throw new IllegalArgumentException("callbackType is invalid");
417          }
418  
419          postCallbackDelayedInternal(callbackType, action, token, delayMillis);
420      }

继续跟踪postCallbackDelayedInternal方法

 private void postCallbackDelayedInternal(int callbackType,
423              Object action, Object token, long delayMillis) {
424          if (DEBUG_FRAMES) {
425              Log.d(TAG, "PostCallback: type=" + callbackType
426                      + ", action=" + action + ", token=" + token
427                      + ", delayMillis=" + delayMillis);
428          }
429  
430          synchronized (mLock) {
431              final long now = SystemClock.uptimeMillis();
432              final long dueTime = now + delayMillis;
433              mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
434  
435              if (dueTime <= now) {
436                  scheduleFrameLocked(now);
437              } else {
438                  Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
439                  msg.arg1 = callbackType;
440                  msg.setAsynchronous(true);
441                  mHandler.sendMessageAtTime(msg, dueTime);
442              }
443          }
444      }

大家在这里可以发现,使用的是Handler Message机制。我们的逻辑在这个类里边 Runnable action。我们回到ViewRootImpl类里的scheduleTraversals方法,其第二个参数mTraversalRunnable 就是TraversalRunnable对象,我们看下该TraversalRunnable类。

 final class TraversalRunnable implements Runnable {
7188          @Override
7189          public void run() {
7190              doTraversal();
7191          }
7192      }

发现TraversalRunnable 是Runnable子类,同时也是ViewRootImpl的内部类。我们看下 doTraversal();方法。doTraversal就是遍历View树。

   void doTraversal() {
1455          if (mTraversalScheduled) {
1456              mTraversalScheduled = false;
1457              mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
1458  
1459              if (mProfile) {
1460                  Debug.startMethodTracing("ViewAncestor");
1461              }
1462  
1463              performTraversals();
1464  
1465              if (mProfile) {
1466                  Debug.stopMethodTracing();
1467                  mProfile = false;
1468              }
1469          }
1470      }

performTraversals();就是开始遍历View树。这个方法非常之长,就不贴源码了,只把重要代码贴出来
final View host = mView;//把decoView赋值为局部变量。另外它里面包含了三个重要的方法

 1.
 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
2262                      int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
2263  
2264                      if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed!  mWidth="
2265                              + mWidth + " measuredWidth=" + host.getMeasuredWidth()
2266                              + " mHeight=" + mHeight
2267                              + " measuredHeight=" + host.getMeasuredHeight()
2268                              + " coveredInsetsChanged=" + contentInsetsChanged);
2269  
2270                       // Ask host how big it wants to be
2271                      performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
      

//执行View的测量
2. performLayout(lp, mWidth, mHeight);//布局的摆放
3. performDraw();//View的绘制
我们详细的看下这三个方法。
第一个方法是View的测量,里面有一个重要的概念——测量的规则。我们要对View树进行测量,首先要从最顶层的decoView开始,我们要知道当亲decoView的大小。
我们看下getRootMeasureSpec()方法。

 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
2949          int measureSpec;
2950          switch (rootDimension) {
2951          //窗口无法调整大小。强制根视图为WindowSize
2952          case ViewGroup.LayoutParams.MATCH_PARENT:
2953              // Window can't resize. Force root view to be windowSize.
2954              measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2955              break;
                   //窗口可以调整大小。为根视图设置最大大小。
2956          case ViewGroup.LayoutParams.WRAP_CONTENT:
2957              // Window can resize. Set max size for root view.
2958              measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2959              break;
2960          default:
2961              // Window wants to be an exact size. Force root view to be that size.
2962              measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2963              break;
2964          }
2965          return measureSpec;
2966      }
发布了208 篇原创文章 · 获赞 15 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qczg_wxg/article/details/103199870