android6.0 Activity(二) View创建过程

转载: https://blog.csdn.net/kc58236582/article/details/52411791


每一个Activity组件都有一个关联的Window对象,用来描述一个应用程序窗口。每一个应用程序窗口内部又包含有一个View对象,用来描述应用程序窗口的视图。应用程序窗口视图是真正用来实现UI内容和布局的,也就是说,每一个Activity组件的UI内容和布局都是通过与其所关联的一个Window对象的内部的一个View对象来实现的。在本文中,我们就详细分析应用程序窗口视图的创建过程。

应用程序窗口内部所包含的视图对象的实际类型为DecorView。DecorView类继承了View类,是作为容器(ViewGroup)来使用的,它的实现如图

每一个Activity对象都有一个关联的ViewRootImpl对象,相当于是MVC模型中的Controller,它有以下职责:

        1. 负责为应用程序窗口视图创建Surface。

        2. 配合WindowManagerService来管理系统的应用程序窗口。

        3. 负责管理、布局和渲染应用程序窗口视图的UI。

从前面Android应用程序启动过程源代码分析一文可以知道,Activity组件在启动的过程中,会调用ActivityThread类的成员函数handleLaunchActivity,用来创建以及首次激活Activity组件,因此,接下来我们就从这个函数开始,具体分析应用程序窗口的视图对象及其所关联的ViewRootImpl对象的创建过程,如图所示

setContentView中创建DecorView对象

一般在Activity的子类的onCreate方法中都会实现setContentView函数,我们来看Activity的这个函数:


  
  
  1. public void setContentView(View view) {
  2. getWindow().setContentView(view);
  3. initWindowDecorActionBar();
  4. }

调用了PhoneWindow的setContentView函数,而在这个函数中调用了installDecor函数来创建DecorView对象


  
  
  1. @ Override
  2. public void setContentView (View view, ViewGroup.LayoutParams params) {
  3. // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
  4. // decor, when theme attributes and the like are crystalized. Do not check the feature
  5. // before this happens.
  6. if (mContentParent == null) {
  7. installDecor();
  8. } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
  9. mContentParent.removeAllViews();
  10. }
  11. if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
  12. view.setLayoutParams(params);
  13. final Scene newScene = new Scene(mContentParent, view);
  14. transitionTo(newScene);
  15. } else {
  16. mContentParent.addView(view, params);
  17. }
  18. mContentParent.requestApplyInsets();
  19. final Callback cb = getCallback();
  20. if (cb != null && !isDestroyed()) {
  21. cb.onContentChanged();
  22. }
  23. }

在installDecor函数中调用了generateDecor函数来创建DecorView


  
  
  1. private void installDecor() {
  2. if (mDecor == null) {
  3. mDecor = generateDecor();
  4. ......

  
  
  1. protected DecorView generateDecor() {
  2. return new DecorView(getContext(), -1);
  3. }


创建ViewRootImpl对象

下面我们再从ActivityThread的handleResumeActivity函数看,先调用了performResumeActivity函数来查找这个Activity,后面主要调用了WindowManager的addView函数。


  
  
  1. final void handleResumeActivity(IBinder token,
  2. boolean clearHide, boolean isForward, boolean reallyResume) {
  3. // If we are getting ready to gc after going to the background, well
  4. // we are back active so skip it.
  5. unscheduleGcIdler();
  6. mSomeActivitiesChanged = true;
  7. // TODO Push resumeArgs into the activity for consideration
  8. ActivityClientRecord r = performResumeActivity(token, clearHide);
  9. if (r != null) {
  10. final Activity a = r.activity;
  11. if (localLOGV) Slog.v(
  12. TAG, "Resume " + r + " started activity: " +
  13. a.mStartedActivity + ", hideForNow: " + r.hideForNow
  14. + ", finished: " + a.mFinished);
  15. final int forwardBit = isForward ?
  16. WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
  17. // If the window hasn't yet been added to the window manager,
  18. // and this guy didn't finish itself or start another activity,
  19. // then go ahead and add the window.
  20. boolean willBeVisible = !a.mStartedActivity;
  21. if (!willBeVisible) {
  22. try {
  23. willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
  24. a.getActivityToken());
  25. } catch (RemoteException e) {
  26. }
  27. }
  28. if (r.window == null && !a.mFinished && willBeVisible) {
  29. r.window = r.activity.getWindow();
  30. View decor = r.window.getDecorView();
  31. decor.setVisibility(View.INVISIBLE);
  32. ViewManager wm = a.getWindowManager();
  33. WindowManager.LayoutParams l = r.window.getAttributes();
  34. a.mDecor = decor;
  35. l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
  36. l.softInputMode |= forwardBit;
  37. if (a.mVisibleFromClient) {
  38. a.mWindowAdded = true;
  39. wm.addView(decor, l);
  40. }

我们先来看performResumeActivity函数,这个函数主要是根据token来寻找ActivityClientRecord,然后调用了Activity的performResume方法。


  
  
  1. public final ActivityClientRecord performResumeActivity(IBinder token,
  2. boolean clearHide) {
  3. ActivityClientRecord r = mActivities.get(token);
  4. if (localLOGV) Slog.v(TAG, "Performing resume of " + r
  5. + " finished=" + r.activity.mFinished);
  6. if (r != null && !r.activity.mFinished) {
  7. if (clearHide) {
  8. r.hideForNow = false;
  9. r.activity.mStartedActivity = false;
  10. }
  11. try {
  12. r.activity.onStateNotSaved();
  13. r.activity.mFragments.noteStateNotSaved();
  14. if (r.pendingIntents != null) {
  15. deliverNewIntents(r, r.pendingIntents);
  16. r.pendingIntents = null;
  17. }
  18. if (r.pendingResults != null) {
  19. deliverResults(r, r.pendingResults);
  20. r.pendingResults = null;
  21. }
  22. r.activity.performResume();
  23. EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED,
  24. UserHandle.myUserId(), r.activity.getComponentName().getClassName());
  25. r.paused = false;
  26. r.stopped = false;
  27. r.state = null;
  28. r.persistentState = null;
  29. } catch (Exception e) {
  30. if (!mInstrumentation.onException(r.activity, e)) {
  31. throw new RuntimeException(
  32. "Unable to resume activity "
  33. + r.intent.getComponent().toShortString()
  34. + ": " + e.toString(), e);
  35. }
  36. }
  37. }
  38. return r;
  39. }

后面有调用了Activity的getWindowManager方法获取WindowManager,之前的博客有分析过,这个WindowManager就是WindowManagerImpl对象。下面也就是调用了WindowManagerImpl的addView函数。

我们来看WindowManagerImpl的addView函数,其实就是调用了WindowManagerGlobal的addView函数


  
  
  1. @ Override
  2. public void addView (@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
  3. applyDefaultToken(params);
  4. mGlobal.addView(view, params, mDisplay, mParentWindow);
  5. }

之前也分析过WindowManagerGlobal,它有3个重要的成员变量:


  
  
  1. private final ArrayList<View> mViews = new ArrayList<View>(); //所有的DecorView对象
  2. private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>(); //所有的ViewRootImpl对象
  3. private final ArrayList<WindowManager.LayoutParams> mParams = //所有顶层View的layout参数
  4. new ArrayList<WindowManager.LayoutParams>();

我们再来看WindowManagerGlobal的addView函数,这个函数先是查找是否已经在WindowManagerGlobal中已经有这个view,如果有的话就调用其ViewRootImpl的doDie函数中主要是调用WindowManagerGlobal函数去除这个ViewRootImpl对象,在这个主要是创建了ViewRootImpl,并且把DecorView,RootViewRootImpl,layout参数都保存起来了。然后调用了ViewRootImpl的setView函数。


  
  
  1. public void addView(View view, ViewGroup.LayoutParams params,
  2. Display display, Window parentWindow) {
  3. ......
  4. int index = findViewLocked(view, false); //查找是否有该view,获取其index
  5. if (index >= 0) {
  6. if (mDyingViews.contains(view)) {
  7. // Don't wait for MSG_DIE to make it's way through root's queue.
  8. mRoots.get(index).doDie(); //调用ViewRootImpl的doDie函数
  9. } else {
  10. throw new IllegalStateException( "View " + view
  11. + " has already been added to the window manager.");
  12. }
  13. // The previous removeView() had not completed executing. Now it has.
  14. }
  15. ......
  16. root = new ViewRootImpl(view.getContext(), display); //新建ViewRootImpl对象
  17. view.setLayoutParams(wparams);
  18. mViews.add(view); //成员变量增加
  19. mRoots.add(root);
  20. mParams.add(wparams);
  21. }
  22. // do this last because it fires off messages to start doing things
  23. try {
  24. root.setView(view, wparams, panelParentView); //调用ViewRootImpl的setView函数
  25. } catch (RuntimeException e) {
  26. // BadTokenException or InvalidDisplayException, clean up.
  27. synchronized (mLock) {
  28. final int index = findViewLocked(view, false);
  29. if (index >= 0) {
  30. removeViewLocked(index, true);
  31. }
  32. }
  33. throw e;
  34. }
  35. }
我们再来看下ViewRootImpl的doDie函数中最后有下面一行代码:

WindowManagerGlobal.getInstance().doRemoveView(this);
  
  

而在WindowManagerGlobal中就是去除相关所有的保存。


  
  
  1. void doRemoveView(ViewRootImpl root) {
  2. synchronized (mLock) {
  3. final int index = mRoots.indexOf(root);
  4. if (index >= 0) {
  5. mRoots.remove(index);
  6. mParams.remove(index);
  7. final View view = mViews.remove(index);
  8. mDyingViews.remove(view);
  9. }
  10. }
  11. if (HardwareRenderer.sTrimForeground && HardwareRenderer.isAvailable()) {
  12. doTrimForeground();
  13. }
  14. }


ViewRootImpl的setView函数

下面我们再来看看ViewRootImpl的setView函数:


  
  
  1. public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  2. synchronized ( this) {
  3. if (mView == null) {
  4. mView = view;
  5. mAttachInfo.mDisplayState = mDisplay.getState();
  6. mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
  7. mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
  8. mFallbackEventHandler.setView(view);
  9. mWindowAttributes.copyFrom(attrs);
  10. if (mWindowAttributes.packageName == null) {
  11. mWindowAttributes.packageName = mBasePackageName;
  12. }
  13. attrs = mWindowAttributes;
  14. // Keep track of the actual window flags supplied by the client.
  15. mClientWindowLayoutFlags = attrs.flags;
  16. setAccessibilityFocus(null, null);
  17. if (view instanceof RootViewSurfaceTaker) {
  18. mSurfaceHolderCallback =
  19. ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
  20. if (mSurfaceHolderCallback != null) {
  21. mSurfaceHolder = new TakenSurfaceHolder();
  22. mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
  23. }
  24. }
  25. // Compute surface insets required to draw at specified Z value.
  26. // TODO: Use real shadow insets for a constant max Z.
  27. if (!attrs.hasManualSurfaceInsets) {
  28. final int surfaceInset = ( int) Math. ceil(view.getZ() * 2);
  29. attrs.surfaceInsets. set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
  30. }
  31. CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
  32. mTranslator = compatibilityInfo.getTranslator();
  33. // If the application owns the surface, don't enable hardware acceleration
  34. if (mSurfaceHolder == null) {
  35. enableHardwareAcceleration(attrs);
  36. }
  37. boolean restore = false;
  38. if (mTranslator != null) {
  39. mSurface.setCompatibilityTranslator(mTranslator);
  40. restore = true;
  41. attrs.backup();
  42. mTranslator.translateWindowLayout(attrs);
  43. }
  44. if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
  45. if (!compatibilityInfo.supportsScreen()) {
  46. attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
  47. mLastInCompatMode = true;
  48. }
  49. mSoftInputMode = attrs.softInputMode;
  50. mWindowAttributesChanged = true;
  51. mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
  52. mAttachInfo.mRootView = view;
  53. mAttachInfo.mScalingRequired = mTranslator != null;
  54. mAttachInfo.mApplicationScale =
  55. mTranslator == null ? 1.0f : mTranslator.applicationScale;
  56. if (panelParentView != null) {
  57. mAttachInfo.mPanelParentWindowToken
  58. = panelParentView.getApplicationWindowToken();
  59. }
  60. mAdded = true;
  61. int res; /* = WindowManagerImpl.ADD_OKAY; */
  62. // Schedule the first layout -before- adding to the window
  63. // manager, to make sure we do the relayout before receiving
  64. // any other events from the system.
  65. requestLayout(); //绘制UI布局
  66. if ((mWindowAttributes.inputFeatures
  67. & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
  68. mInputChannel = new InputChannel(); //创建按键通道
  69. }
  70. try {
  71. mOrigWindowType = mWindowAttributes.type;
  72. mAttachInfo.mRecomputeGlobalAttributes = true;
  73. collectViewAttributes();
  74. res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
  75. getHostVisibility(), mDisplay.getDisplayId(),
  76. mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
  77. mAttachInfo.mOutsets, mInputChannel);
  78. } catch (RemoteException e) {
  79. mAdded = false;
  80. mView = null;
  81. mAttachInfo.mRootView = null;
  82. mInputChannel = null;
  83. mFallbackEventHandler.setView(null);
  84. unscheduleTraversals();
  85. setAccessibilityFocus(null, null);
  86. throw new RuntimeException( "Adding window failed", e);
  87. } finally {
  88. if (restore) {
  89. attrs.restore();
  90. }
  91. }
  92. if (mTranslator != null) {
  93. mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
  94. }
  95. mPendingOverscanInsets. set( 0, 0, 0, 0);
  96. mPendingContentInsets. set(mAttachInfo.mContentInsets);
  97. mPendingStableInsets. set(mAttachInfo.mStableInsets);
  98. mPendingVisibleInsets. set( 0, 0, 0, 0);
  99. if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
  100. if (res < WindowManagerGlobal.ADD_OKAY) {
  101. mAttachInfo.mRootView = null;
  102. mAdded = false;
  103. mFallbackEventHandler.setView(null);
  104. unscheduleTraversals();
  105. setAccessibilityFocus(null, null);
  106. switch (res) {
  107. case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
  108. case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
  109. throw new WindowManager.BadTokenException(
  110. "Unable to add window -- token " + attrs.token
  111. + " is not valid; is your activity running?");
  112. case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
  113. throw new WindowManager.BadTokenException(
  114. "Unable to add window -- token " + attrs.token
  115. + " is not for an application");
  116. case WindowManagerGlobal.ADD_APP_EXITING:
  117. throw new WindowManager.BadTokenException(
  118. "Unable to add window -- app for token " + attrs.token
  119. + " is exiting");
  120. case WindowManagerGlobal.ADD_DUPLICATE_ADD:
  121. throw new WindowManager.BadTokenException(
  122. "Unable to add window -- window " + mWindow
  123. + " has already been added");
  124. case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
  125. // Silently ignore -- we would have just removed it
  126. // right away, anyway.
  127. return;
  128. case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
  129. throw new WindowManager.BadTokenException(
  130. "Unable to add window " + mWindow +
  131. " -- another window of this type already exists");
  132. case WindowManagerGlobal.ADD_PERMISSION_DENIED:
  133. throw new WindowManager.BadTokenException(
  134. "Unable to add window " + mWindow +
  135. " -- permission denied for this window type");
  136. case WindowManagerGlobal.ADD_INVALID_DISPLAY:
  137. throw new WindowManager.InvalidDisplayException(
  138. "Unable to add window " + mWindow +
  139. " -- the specified display can not be found");
  140. case WindowManagerGlobal.ADD_INVALID_TYPE:
  141. throw new WindowManager.InvalidDisplayException(
  142. "Unable to add window " + mWindow
  143. + " -- the specified window type is not valid");
  144. }
  145. throw new RuntimeException(
  146. "Unable to add window -- unknown error code " + res);
  147. }
  148. if (view instanceof RootViewSurfaceTaker) {
  149. mInputQueueCallback =
  150. ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
  151. }
  152. if (mInputChannel != null) {
  153. if (mInputQueueCallback != null) {
  154. mInputQueue = new InputQueue();
  155. mInputQueueCallback.onInputQueueCreated(mInputQueue);
  156. }
  157. mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, //创建按键应用层接受对象
  158. Looper.myLooper());
  159. }
  160. view.assignParent( this);
  161. mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
  162. mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
  163. if (mAccessibilityManager.isEnabled()) {
  164. mAccessibilityInteractionConnectionManager.ensureConnection();
  165. }
  166. if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
  167. view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
  168. }
  169. // Set up the input pipeline.
  170. CharSequence counterSuffix = attrs.getTitle();
  171. mSyntheticInputStage = new SyntheticInputStage(); //按键的一些流程类
  172. InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
  173. InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
  174. "aq:native-post-ime:" + counterSuffix);
  175. InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
  176. InputStage imeStage = new ImeInputStage(earlyPostImeStage,
  177. "aq:ime:" + counterSuffix);
  178. InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
  179. InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
  180. "aq:native-pre-ime:" + counterSuffix);
  181. mFirstInputStage = nativePreImeStage;
  182. mFirstPostImeInputStage = earlyPostImeStage;
  183. mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
  184. }
  185. }
  186. }

这个函数主要是调用了requestLayout函数来对应用窗口的UI布局,然后创建了InputChannel。调用ViewRoot类的静态成员变量sWindowSession所描述的一个类型为Session的Binder代理对象的成员函数add来请求WindowManagerService增加一个WindowState对象,以便可以用来描述当前正在处理的一个ViewRootImpl所关联的一个应用程序窗口。

最后创建了WindowInputEventReceiver应用层的按键接受,以及一些按键在应用层的流程的相关类。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值