我们看下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 }