WindowInsets流程:
setContentView过程可以分为两部分,一部分是构建DecorView布局,一部分是将布局添加到window中。主要看添加到window流程:ActivityThread.handleResumeActivity-WindowManager.addView-WIndowManagerImpl.addView-WindowManagerGloble.addView-ViewRootImpl.setView-.requestLayout-.scheduleTraversals-.TraversalRunnable-.doTraversal-.performTraversals-.dispatchApplyInsets(View host)-host.dispatchApplyWindowInsets(host其实就是PhoneWindow中的DecorView),说明一下,performTranversals方法依次执行dispatchApplyInsets、performMeasure、performLayout和performDraw,最终完成View的绘制流程.
接下来就是View和ViewGroup层次的WindowInsets调用流程了,由上面可知最后调用DecorView.dispatchApplyWindowInsets,而它直接调用ViewGroup的dispatchApplyWindowInsets,因为DecorView、FrameLayout都没有重写dispatchApplyWindowInsets方法
@Override public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { insets = super.dispatchApplyWindowInsets(insets); if (!insets.isConsumed()) { final int count = getChildCount(); for (int i = 0; i < count; i++) { insets = getChildAt(i).dispatchApplyWindowInsets(insets); if (insets.isConsumed()) { break; } } } return insets; }
开头就直接调用了View的dispatchApplyWindowInsets处理insets,然后直接判断是否消费,如果没有消费就依次分发给child,直到有child消费insets就退出,下面先看View的dispatchApplyWindowInsets:
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { try { //将PLAGS3_APPLYING_INSETS注入mPrivateFlag3 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); } else { return onApplyWindowInsets(insets); } } finally { //将PLAGS3_APPLYING_INSETS移除mPrivateFlag3 mPrivateFlag3 &= ~PFLAG3_APPLYING_INSETS; }
如果向View注册了OnApplyWindowInsetsListener监听器,就直接用监听器截取Insets操作返回,否则执行onApplyWindowInsets方法,因为DecorView没有注册监听器但重写了onApplyWindowInsets方法,所以执行DecorView的onApplyWindowInsets:
@Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { ... insets = updateColorViews(insets, true/animate/); insets = updateStatusGuard(insets); updateNavigationGuard(insets); ... return insets }
在updateColorViews方法中,执行了两次updateColorViewInt方法,第一次传入的参数是mNavigationColorViewState,第二次传入mStatusColorViewState,代码如下:
private WindowInsets updateColorViews(WindowInsets insets, boolean animate) { ...... updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mNavigationBarColor, navBarSize, navBarToRightEdge, 0 /rightInset/, animate && !disallowAnimate); ...... updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor, mLastTopInset, false /matchVertical/, statusBarRightInset, animate && !disallowAnimate); }
结合上面传入参数的名字,能够看出这段代码就是向DecorView中添加窗口顶部的StatusBar状态栏(显示电量、手机信号)的占位View和底部NavigationBar导航栏(三个大按钮的虚拟栏)的占位View,因为他们只是添加一个设置了背景色的View,所以只是占位用。代码如下:
private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color, int size, boolean verticalBar, int rightMargin, boolean animate) { ...... state.view = view = new View(mContext); view.setBackgroundColor(color); view.setTransitionName(state.transitionName); view.setId(state.id); visibilityChanged = true; view.setVisibility(INVISIBLE); state.targetVisibility = VISIBLE; LayoutParams lp = new LayoutParams(resolvedWidth, resolvedHeight, resolvedGravity); lp.rightMargin = rightMargin; addView(view, lp);//向DecorView中添加StatusBar或NavigationBar ...... }
后面接着的updateStatusGuard和updateNavigationGuard方法作用还在研究。
StatusBar流程:
zygote-SystemServer.main-SystemServer.run-SystemServer.startOtherServices-ActivityManagerService.systemReady-SystemServer.startSystemUi-systemUIService.onCreate-SystemUIApplication.startServicesIfNeeded-SystemBars.start-ServiceMonitor.start-SystemBars.onNoService-SystemBars.createStatusBarFromConfig(R.string.config_statusBarComponent表示PhoneStatusBar)-PhoneStatusBar.start-BaseSatusBar.start-PhoneStatusBar.createAndAddWindows-PhoneStatusBar.addStatusBarWindow-PhoneStatusBar.makeStatusBarView
其中makeStatusBarView实例化StatusBarWindow,也就是真实显示statusbar各种图标的布局,然后在addStatusBarWindow中进行添加操作:
private void addStatusBarWindow() { makeStatusBarView(); mStatusBarWindowManager = new StatusBarWindowManager(mContext); mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());//mStatusBarWindow是已经实例化的statsbar布局 }
最后来看StatusBarWindowManager的add方法:
public void add(View statusBarView, int barHeight) { ...... mWindowmanager.addView(mStatusBarView, mLp); ...... }
很明显,这里向window添加了mStatusBarView布局,也就是状态栏布局。