本篇文章基于 Android N - 7.1.1 主要分析下 Activity 中 setContentView 的流程,但是此时 UI 还没有显示出来;
真正显示 ui 是在 onResume 方法调用后,这个流程会创建 ViewRootImpl 类,并设置 setView 操作;
1 回顾 我们来回顾下 activity 的 onResume 方法的执行。
1.1 ActivityThread 核心的入口是在 handleResumeActivity 方法中;
1.1.1 handleResumeActivity 我们来看看核心的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 final void handleResumeActivity (IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) { ActivityClientRecord r = mActivities.get(token); ... ... ... r = performResumeActivity(token, clearHide, reason); if (r != null ) { final Activity a = r.activity; ... ... ... if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (r.mPreserveWindow) { a.mWindowAdded = true ; r.mPreserveWindow = false ; ViewRootImpl impl = decor.getViewRootImpl(); if (impl != null ) { impl.notifyChildRebuilt(); } } if (a.mVisibleFromClient && !a.mWindowAdded) { a.mWindowAdded = true ; wm.addView(decor, l); } } else if (!willBeVisible) { if (localLOGV) Slog.v( TAG, "Launch " + r + " mStartedActivity set" ); r.hideForNow = true ; } cleanUpPendingRemoveWindows(r, false ); if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) { if (r.newConfig != null ) { performConfigurationChangedForActivity(r, r.newConfig, REPORT_TO_ACTIVITY); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig " + r.activity.mCurrentConfig); r.newConfig = null ; } if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward); WindowManager.LayoutParams l = r.window.getAttributes(); if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != forwardBit) { l.softInputMode = (l.softInputMode & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)) | forwardBit; if (r.activity.mVisibleFromClient) { ViewManager wm = a.getWindowManager(); View decor = r.window.getDecorView(); wm.updateViewLayout(decor, l); } } r.activity.mVisibleFromServer = true ; mNumVisibleActivities++; if (r.activity.mVisibleFromClient) { r.activity.makeVisible(); } } ... ... ... } else { try { ActivityManagerNative.getDefault() .finishActivity(token, Activity.RESULT_CANCELED, null , Activity.DONT_FINISH_TASK_WITH_ACTIVITY); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } }
这里,我们省略了一些不重要的代码,关注核心!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; ... ... ... if (a.mVisibleFromClient && !a.mWindowAdded) { a.mWindowAdded = true ; wm.addView(decor, l); }
可以看到,核心的逻辑在 wm.addView(decor, l) 这个地方!
decor:我们的 DecorView;
l:PhoneWindow 中的布局参数;
2 WindowManagerImpl 这里我们进入了 WindowManagerImpl,这个类是在 activity.attach 方法中创建的。
2.1 new WindowManagerImpl 我们来看下 WindowManagerImpl 的创建;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public final class WindowManagerImpl implements WindowManager { private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); private final Context mContext; private final Window mParentWindow; private IBinder mDefaultToken; public WindowManagerImpl (Context context) { this (context, null ); } private WindowManagerImpl (Context context, Window parentWindow) { mContext = context; mParentWindow = parentWindow; }
WindowManager 又继承了 ViewManager:
1 2 3 public interface WindowManager extends ViewManager { ... ... ... }
ViewManager 是一个接口,提供了两个函数接口:
1 2 3 4 public interface ViewManager { public void addView (View view, ViewGroup.LayoutParams params) ; public void updateViewLayout (View view, ViewGroup.LayoutParams params) ; }
根据注释:
addView 的操作主要是:添加一个 view 到一个 window,同时分配布局属性给 view;
会抛出如下异常:
android.view.WindowManager.BadTokenException:在没有移除已经存在的 view 的情况下,添加新的 view,也就是说一个 window 对应一个 View!
android.view.WindowManager.InvalidDisplayException:当我们讲一个 window 添加到 display,但是其不存在或者无效的时候;
可以看到,根据继承和实现的关系,我们知道:
WindowManagerImpl: 是最终的实现类,和 window、view 相关的操作都在其内部实现;
WindowManager:提供了和 window 相关的操作,已经一些和 window 相关的常量,共有变量,异常定义等等;
ViewManager:提供了和 view 添加和更新相关的操作;
各司其职,各司其职!
2.2 addView 我们来看看
1 2 3 4 5 6 7 @Override public void addView (@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); }
2.2.1 applyDefaultToken 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private void applyDefaultToken (@NonNull ViewGroup.LayoutParams params) { if (mDefaultToken != null && mParentWindow == null ) { if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams" ); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (wparams.token == null ) { wparams.token = mDefaultToken; } } }
如果 mParentWindow 为 null 的话,那么这里会分配默认的 token;
3 WindowManagerGlobal WindowManagerImpl 将操作交给 WindowManagerGlobal 完成,这里使用了桥接模式;
3.1 getInstance 他是一个单例模式:
1 2 3 4 5 6 7 8 9 10 private static WindowManagerGlobal sDefaultWindowManager;public static WindowManagerGlobal getInstance () { synchronized (WindowManagerGlobal.class) { if (sDefaultWindowManager == null ) { sDefaultWindowManager = new WindowManagerGlobal(); } return sDefaultWindowManager; } }
这个不多说了;
3.2 addView 添加 view:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 public void addView (View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { if (view == null ) { throw new IllegalArgumentException("view must not be null" ); } if (display == null ) { throw new IllegalArgumentException("display must not be null" ); } if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams" ); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (parentWindow != null ) { parentWindow.adjustLayoutParamsForSubWindow(wparams); } else { final Context context = view.getContext(); if (context != null && (context.getApplicationInfo().flags & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0 ) { wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } } ViewRootImpl root; View panelParentView = null ; synchronized (mLock) { if (mSystemPropertyUpdater == null ) { mSystemPropertyUpdater = new Runnable() { @Override public void run () { synchronized (mLock) { for (int i = mRoots.size() - 1 ; i >= 0 ; --i) { mRoots.get(i).loadSystemProperties(); } } } }; SystemProperties.addChangeCallback(mSystemPropertyUpdater); } int index = findViewLocked(view, false ); if (index >= 0 ) { if (mDyingViews.contains(view)) { mRoots.get(index).doDie(); } else { throw new IllegalStateException("View " + view + " has already been added to the window manager." ); } } if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { final int count = mViews.size(); for (int i = 0 ; i < count; i++) { if (mRoots.get(i).mWindow.asBinder() == wparams.token) { panelParentView = mViews.get(i); } } } root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams); } try { root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { synchronized (mLock) { final int index = findViewLocked(view, false ); if (index >= 0 ) { removeViewLocked(index, true ); } } throw e; } }
WindowManagerGlobal 内部有如下的 list,作用如下:
1 2 3 4 5 6 7 8 9 10 11 12 private final ArrayList<View> mViews = new ArrayList<View>();private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>(); private final ArraySet<View> mDyingViews = new ArraySet<View>();
不多说了;
3.3 getWindowSession 创建一个 window session:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public static IWindowSession getWindowSession () { synchronized (WindowManagerGlobal.class) { if (sWindowSession == null ) { try { InputMethodManager imm = InputMethodManager.getInstance(); IWindowManager windowManager = getWindowManagerService(); sWindowSession = windowManager.openSession( new IWindowSessionCallback.Stub() { @Override public void onAnimatorScaleChanged (float scale) { ValueAnimator.setDurationScale(scale); } }, imm.getClient(), imm.getInputContext()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowSession; } }
WindowManagerGlobal 内部还有如下的属性:
1 2 private static IWindowManager sWindowManagerService; private static IWindowSession sWindowSession;
可以看到,这里的 sWindowSession 是一个 IWindowSession 类型的实例;
3.3.1 getWindowManagerService 获得 wms 的代理对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static IWindowManager getWindowManagerService () { synchronized (WindowManagerGlobal.class) { if (sWindowManagerService == null ) { sWindowManagerService = IWindowManager.Stub.asInterface( ServiceManager.getService("window" )); try { sWindowManagerService = getWindowManagerService(); ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowManagerService; } }
4 Window(PhoneWindow) 其实这里的 parentWindow 是 PhoneWindow:
4.1 adjustLayoutParamsForSubWindow 该方法的作用是针对于 sub window 调整下布局参数!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 void adjustLayoutParamsForSubWindow (WindowManager.LayoutParams wp) { CharSequence curTitle = wp.getTitle(); if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { if (wp.token == null ) { View decor = peekDecorView(); if (decor != null ) { wp.token = decor.getWindowToken(); } } if (curTitle == null || curTitle.length() == 0 ) { final StringBuilder title = new StringBuilder(32 ); if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA) { title.append("Media" ); } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY) { title.append("MediaOvr" ); } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { title.append("Panel" ); } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL) { title.append("SubPanel" ); } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL) { title.append("AboveSubPanel" ); } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG) { title.append("AtchDlg" ); } else { title.append(wp.type); } if (mAppName != null ) { title.append(":" ).append(mAppName); } wp.setTitle(title); } } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW && wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { if (curTitle == null || curTitle.length() == 0 ) { final StringBuilder title = new StringBuilder(32 ); title.append("Sys" ).append(wp.type); if (mAppName != null ) { title.append(":" ).append(mAppName); } wp.setTitle(title); } } else { if (wp.token == null ) { wp.token = mContainer == null ? mAppToken : mContainer.mAppToken; } if ((curTitle == null || curTitle.length() == 0 ) && mAppName != null ) { wp.setTitle(mAppName); } } if (wp.packageName == null ) { wp.packageName = mContext.getPackageName(); } if (mHardwareAccelerated || (mWindowAttributes.flags & FLAG_HARDWARE_ACCELERATED) != 0 ) { wp.flags |= FLAG_HARDWARE_ACCELERATED; } }
这个方法主要是针对于不同的 window 做不同的处理;
system window 是不会有 token 的;
sub window 的 token 来自 DecorView(View).mAttachInfo.mWindowToken ,通过 View.getWindowToken() 获得;
我们再来看看几个方法:
peekDecorView 返回的是 DecorView,这个可以从前面文章看出来:
1 2 3 4 5 6 @Override public final View peekDecorView () { return mDecor; }
decor.getWindowToken(),实际上是父类 View 的方法:
1 2 3 public IBinder getWindowToken () { return mAttachInfo != null ? mAttachInfo.mWindowToken : null ; }
关于这个 mAttachInfo 我们后面再看;
5 ViewRootImpl 1 2 3 @SuppressWarnings ({"EmptyCatchBlock" , "PointlessBooleanExpression" })public final class ViewRootImpl implements ViewParent , View .AttachInfo .Callbacks , ThreadedRenderer .HardwareDrawCallbacks {
可以看到 ViewRootImpl 实现了 ViewParent 接口,View.AttachInfo.Callbacks 接口,ThreadedRenderer.HardwareDrawCallbacks 接口;
5.1 new ViewRootImpl ViewRootImpl 内部的成员变量很多,这里我们来看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public ViewRootImpl (Context context, Display display) { mContext = context; mWindowSession = WindowManagerGlobal.getWindowSession(); mDisplay = display; mBasePackageName = context.getBasePackageName(); mThread = Thread.currentThread(); mLocation = new WindowLeaked(null ); mLocation.fillInStackTrace(); mWidth = -1 ; mHeight = -1 ; mDirty = new Rect(); mTempRect = new Rect(); mVisRect = new Rect(); mWinFrame = new Rect(); mWindow = new W(this ); mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; mViewVisibility = View.GONE; mTransparentRegion = new Region(); mPreviousTransparentRegion = new Region(); mFirst = true ; mAdded = false ; mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this , mHandler, this ); mAccessibilityManager = AccessibilityManager.getInstance(context); mAccessibilityInteractionConnectionManager = new AccessibilityInteractionConnectionManager(); mAccessibilityManager.addAccessibilityStateChangeListener( mAccessibilityInteractionConnectionManager); mHighContrastTextManager = new HighContrastTextManager(); mAccessibilityManager.addHighTextContrastStateChangeListener( mHighContrastTextManager); mViewConfiguration = ViewConfiguration.get(context); mDensity = context.getResources().getDisplayMetrics().densityDpi; mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi; mFallbackEventHandler = new PhoneFallbackEventHandler(context); mChoreographer = Choreographer.getInstance(); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); loadSystemProperties(); }
我们看到了变量还是很多的,这里一起列举下核心的几个:
W mWindow:
mWindowSession:
下面的还回遇到一些重要的成员变量,我们也在这里一起来看看:
SurfaceHolder.Callback2 mSurfaceHolderCallback :
BaseSurfaceHolder mSurfaceHolder :
5.2 setView - 核心代码 添加 View,参数 panelParentView 表示要 attach 的 view:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 public void setView (View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this ) { if (mView == null ) { mView = view; mAttachInfo.mDisplayState = mDisplay.getState(); mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); mViewLayoutDirectionInitial = mView.getRawLayoutDirection(); mFallbackEventHandler.setView(view); mWindowAttributes.copyFrom(attrs); if (mWindowAttributes.packageName == null ) { mWindowAttributes.packageName = mBasePackageName; } attrs = mWindowAttributes; setTag(); if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0 ) { Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!" ); } mClientWindowLayoutFlags = attrs.flags; setAccessibilityFocus(null , null ); if (view instanceof RootViewSurfaceTaker) { mSurfaceHolderCallback = ((RootViewSurfaceTaker)view).willYouTakeTheSurface(); if (mSurfaceHolderCallback != null ) { mSurfaceHolder = new TakenSurfaceHolder(); mSurfaceHolder.setFormat(PixelFormat.UNKNOWN); } } if (!attrs.hasManualSurfaceInsets) { attrs.setSurfaceInsets(view, false , true ); } CompatibilityInfo compatibilityInfo = mDisplay.getDisplayAdjustments().getCompatibilityInfo(); mTranslator = compatibilityInfo.getTranslator(); if (mSurfaceHolder == null ) { enableHardwareAcceleration(attrs); } boolean restore = false ; if (mTranslator != null ) { mSurface.setCompatibilityTranslator(mTranslator); restore = true ; attrs.backup(); mTranslator.translateWindowLayout(attrs); } if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs); if (!compatibilityInfo.supportsScreen()) { attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; mLastInCompatMode = true ; } mSoftInputMode = attrs.softInputMode; mWindowAttributesChanged = true ; mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED; mAttachInfo.mRootView = view; mAttachInfo.mScalingRequired = mTranslator != null ; mAttachInfo.mApplicationScale = mTranslator == null ? 1.0f : mTranslator.applicationScale; if (panelParentView != null ) { mAttachInfo.mPanelParentWindowToken = panelParentView.getApplicationWindowToken(); } mAdded = true ; int res; requestLayout(); if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0 ) { mInputChannel = new InputChannel(); } mForceDecorViewVisibility = (mWindowAttributes.privateFlags & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0 ; try { mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true ; collectViewAttributes(); res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); } catch (RemoteException e) { mAdded = false ; mView = null ; mAttachInfo.mRootView = null ; mInputChannel = null ; mFallbackEventHandler.setView(null ); unscheduleTraversals(); setAccessibilityFocus(null , null ); throw new RuntimeException("Adding window failed" , e); } finally { if (restore) { attrs.restore(); } } if (mTranslator != null ) { mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets); } mPendingOverscanInsets.set(0 , 0 , 0 , 0 ); mPendingContentInsets.set(mAttachInfo.mContentInsets); mPendingStableInsets.set(mAttachInfo.mStableInsets); mPendingVisibleInsets.set(0 , 0 , 0 , 0 ); mAttachInfo.mAlwaysConsumeNavBar = (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0 ; mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar; if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow); if (res < WindowManagerGlobal.ADD_OKAY) { mAttachInfo.mRootView = null ; mAdded = false ; mFallbackEventHandler.setView(null ); unscheduleTraversals(); setAccessibilityFocus(null , null ); switch (res) { case WindowManagerGlobal.ADD_BAD_APP_TOKEN: case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN: throw new WindowManager.BadTokenException( "Unable to add window -- token " + attrs.token + " is not valid; is your activity running?" ); case WindowManagerGlobal.ADD_NOT_APP_TOKEN: throw new WindowManager.BadTokenException( "Unable to add window -- token " + attrs.token + " is not for an application" ); case WindowManagerGlobal.ADD_APP_EXITING: throw new WindowManager.BadTokenException( "Unable to add window -- app for token " + attrs.token + " is exiting" ); case WindowManagerGlobal.ADD_DUPLICATE_ADD: throw new WindowManager.BadTokenException( "Unable to add window -- window " + mWindow + " has already been added" ); case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED: return ; case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON: throw new WindowManager.BadTokenException("Unable to add window " + mWindow + " -- another window of type " + mWindowAttributes.type + " already exists" ); case WindowManagerGlobal.ADD_PERMISSION_DENIED: throw new WindowManager.BadTokenException("Unable to add window " + mWindow + " -- permission denied for window type " + mWindowAttributes.type); case WindowManagerGlobal.ADD_INVALID_DISPLAY: throw new WindowManager.InvalidDisplayException("Unable to add window " + mWindow + " -- the specified display can not be found" ); case WindowManagerGlobal.ADD_INVALID_TYPE: throw new WindowManager.InvalidDisplayException("Unable to add window " + mWindow + " -- the specified window type " + mWindowAttributes.type + " is not valid" ); } throw new RuntimeException( "Unable to add window -- unknown error code " + res); } if (view instanceof RootViewSurfaceTaker) { mInputQueueCallback = ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue(); } if (mInputChannel != null ) { if (mInputQueueCallback != null ) { mInputQueue = new InputQueue(); mInputQueueCallback.onInputQueueCreated(mInputQueue); } mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper()); } view.assignParent(this ); mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0 ; mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0 ; if (mAccessibilityManager.isEnabled()) { mAccessibilityInteractionConnectionManager.ensureConnection(); } if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } CharSequence counterSuffix = attrs.getTitle(); mSyntheticInputStage = new SyntheticInputStage(); InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage); InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage, "aq:native-post-ime:" + counterSuffix); InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage); InputStage imeStage = new ImeInputStage(earlyPostImeStage, "aq:ime:" + counterSuffix); InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage); InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage, "aq:native-pre-ime:" + counterSuffix); mFirstInputStage = nativePreImeStage; mFirstPostImeInputStage = earlyPostImeStage; mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix; } } }
我们看到,这个流程还涉及到了 ViewRootImpl 的一些其他核心属性,这里简单看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 View mView WindowManager.LayoutParams mWindowAttributes int mClientWindowLayoutFlags int mOrigWindowType = -1 ; SurfaceHolder.Callback2 mSurfaceHolderCallback; BaseSurfaceHolder mSurfaceHolder; boolean mWindowAttributesChanged = false ; boolean mAdded; final View.AttachInfo mAttachInfo; InputChannel mInputChannel; WindowInputEventReceiver mInputEventReceiver
同样的,还涉及到了 AttachInfo 的一些属性:
5.2.1 View.assignParent 给 View 分配 Parent!
1 2 3 4 5 6 7 8 9 10 11 void assignParent (ViewParent parent) { if (mParent == null ) { mParent = parent; } else if (parent == null ) { mParent = null ; } else { throw new RuntimeException("view " + this + " being added, but" + " it already has a parent" ); } }
我们知道 ViewRootImpl 是实现了 ViewParent 接口的:
1 2 protected ViewParent mParent;
5.3 requestLayout - 核心代码 请求布局;
1 2 3 4 5 6 7 8 9 10 @Override public void requestLayout () { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true ; scheduleTraversals(); } }
可以看到,这里最后调用了 scheduleTraversals 方法!
5.3.1 checkThread 在请求布局的时候,需要检查当前线程是否是 main thread:
1 2 3 4 5 6 7 void checkThread () { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views." ); } }
只有主线程才能操作 ui!
5.4 collectViewAttributes 收集并更新 view 的属性;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private boolean collectViewAttributes () { if (mAttachInfo.mRecomputeGlobalAttributes) { mAttachInfo.mRecomputeGlobalAttributes = false ; boolean oldScreenOn = mAttachInfo.mKeepScreenOn; mAttachInfo.mKeepScreenOn = false ; mAttachInfo.mSystemUiVisibility = 0 ; mAttachInfo.mHasSystemUiListeners = false ; mView.dispatchCollectViewAttributes(mAttachInfo, 0 ); mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility; WindowManager.LayoutParams params = mWindowAttributes; mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params); if (mAttachInfo.mKeepScreenOn != oldScreenOn || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) { applyKeepScreenOnFlag(params); params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility; params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners; mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility); return true ; } } return false ; }
下面就不再多说了;
5.5 loadSystemProperties 加载系统属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public void loadSystemProperties () { mHandler.post(new Runnable() { @Override public void run () { mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false ); profileRendering(mAttachInfo.mHasWindowFocus); if (mAttachInfo.mHardwareRenderer != null ) { if (mAttachInfo.mHardwareRenderer.loadSystemProperties()) { invalidate(); } } boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false ); if (layout != mAttachInfo.mDebugLayout) { mAttachInfo.mDebugLayout = layout; if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) { mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200 ); } } } }); }
这里不再细看。
5.6 scheduleTraversals - 核心 触发视图遍历:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void scheduleTraversals () { if (!mTraversalScheduled) { mTraversalScheduled = true ; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null ); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } }
我们来看看 Choreographer.postCallback 的第一个参数:
Choreographer.CALLBACK_TRAVERSAL :表示该回调是一个绘制回调;
其实在 Choreographer 一共有三种回调类型,分别是:
CALLBACK_INPUT :事件回调;
CALLBACK_ANIMATION :动画回调;
CALLBACK_TRAVERSAL :绘制回调;
对于编舞者,这里就不详细分析了;
5.6.1 TraversalRunnable.run TraversalRunnable 只是一个 runnable,其内部会调用另外一个方法:doTraversal()
1 2 3 4 5 6 7 8 final class TraversalRunnable implements Runnable { @Override public void run () { doTraversal(); } } final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
5.7 doTraversal 开始遍历了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void doTraversal () { if (mTraversalScheduled) { mTraversalScheduled = false ; mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); if (mProfile) { Debug.startMethodTracing("ViewAncestor" ); } performTraversals(); if (mProfile) { Debug.stopMethodTracing(); mProfile = false ; } } }
我们看到,最后调用了 performTraversals 方法!
关于 performTraversals 下一篇文章来分析!
处理 input 事件:
1 2 3 4 5 6 7 void scheduleConsumeBatchedInput () { if (!mConsumeBatchedInputScheduled) { mConsumeBatchedInputScheduled = true ; mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, mConsumedBatchedInputRunnable, null ); } }
这个和之前的逻辑就很类似了!
和之前的逻辑是一样的,只不过是针对于 input 的:
1 2 3 4 5 6 7 8 9 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable = new ConsumeBatchedInputRunnable(); final class ConsumeBatchedInputRunnable implements Runnable { @Override public void run () { doConsumeBatchedInput(mChoreographer.getFrameTimeNanos()); } }
当然对于 input 的处理,这里不是本文的重点!
6 ViewRootImpl.W W 类(这名字,估计 Google 也想不到应该启什么名字了),使用于跨进程通信的,当 wms 需要通知应用客户端去做一些事的时候,那么就会通过 Binder 通信,调用 W 类的相关方法!
而每一个 W 又和一个 ViewRootImpl 相关联,所以 W 的会将操作交给 ViewRootImpl;
6.1 new W 我们来看看 W 的构造器:
1 2 3 4 5 6 7 8 9 10 11 static class W extends IWindow .Stub { private final WeakReference<ViewRootImpl> mViewAncestor; private final IWindowSession mWindowSession; W(ViewRootImpl viewAncestor) { mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); mWindowSession = viewAncestor.mWindowSession; } }
7 AttachInfo 我们知道,如果一个 window 是 sub window 的话,他会被绑定(attach)到令牌 token 一样的 parent window 上,那么这个 AttachInfo 会用保存和 attach 相关的信息;
AttachInfo 是 View 的内部类 !
7.1 new AttachInfo
参数 IWindowSession session :窗口事务;
参数 IWindow window :就是 ViewRootImpl 中的 W 实例:mWindow;
参数 Handler handler :这个是 ViewRootImpl 内部的 mHandler 实例;
1 2 3 4 5 6 7 8 9 10 11 12 13 AttachInfo(IWindowSession session, IWindow window, Display display, ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, Context context) { mSession = session; mWindow = window; mWindowToken = window.asBinder(); mDisplay = display; mViewRootImpl = viewRootImpl; mHandler = handler; mRootCallbacks = effectPlayer; mTreeObserver = new ViewTreeObserver(context); }
关于 ViewTreeObserver 这里就先不关注了。
8 DecorView (RootViewSurfaceTaker) 8.1 willYouTakeTheSurface 是否让 View 持有监听 surface 变化的回调:
1 2 3 public android.view.SurfaceHolder.Callback2 willYouTakeTheSurface () { return mFeatureId < 0 ? mWindow.mTakeSurfaceCallback : null ; }
这里的 mFeatureId 在 activity 的情况下是 -1,所以会返回 null;
是否让 View 持有 InputQueue:
1 2 3 public InputQueue.Callback willYouTakeTheInputQueue () { return mFeatureId < 0 ? mWindow.mTakeInputQueueCallback : null ; }
和上面是一样的!
9 总结 我们来分析下整个流程:
1 2 3 4 5 6 7 8 9 10 ActivityThread -> ActivityThread: 1.handleResumeActivity ActivityThread -> WindowManagerImpl: 2.addView WindowManagerImpl -> ViewRootImpl: 3.new ViewRootImpl ViewRootImpl --> WindowManagerImpl: 4.return root:ViewRootImpl WindowManagerImpl -> ViewRootImpl: 5.setView ViewRootImpl -> ViewRootImpl: 6.requestLayout