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方法
<pre>
@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;
}
</pre>
开头就直接调用了View的dispatchApplyWindowInsets处理insets,然后直接判断是否消费,如果没有消费就依次分发给child,直到有child消费insets就退出,下面先看View的dispatchApplyWindowInsets:
<pre>
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;
}
</pre>
如果向View注册了OnApplyWindowInsetsListener监听器,就直接用监听器截取Insets操作返回,否则执行onApplyWindowInsets方法,因为DecorView没有注册监听器但重写了onApplyWindowInsets方法,所以执行DecorView的onApplyWindowInsets:
<pre>
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
...
insets = updateColorViews(insets, true/animate/);
insets = updateStatusGuard(insets);
updateNavigationGuard(insets);
...
return insets
}
</pre>
在updateColorViews方法中,执行了两次updateColorViewInt方法,第一次传入的参数是mNavigationColorViewState,第二次传入mStatusColorViewState,代码如下:
<pre>
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);
}
</pre>
结合上面传入参数的名字,能够看出这段代码就是向DecorView中添加窗口顶部的StatusBar状态栏(显示电量、手机信号)的占位View和底部NavigationBar导航栏(三个大按钮的虚拟栏)的占位View,因为他们只是添加一个设置了背景色的View,所以只是占位用。代码如下:
<pre>
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
......
}
</pre>
后面接着的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中进行添加操作:
<pre>
private void addStatusBarWindow() {
makeStatusBarView();
mStatusBarWindowManager = new StatusBarWindowManager(mContext);
mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());//mStatusBarWindow是已经实例化的statsbar布局
}
</pre>
最后来看StatusBarWindowManager的add方法:
<pre>
public void add(View statusBarView, int barHeight) {
......
mWindowmanager.addView(mStatusBarView, mLp);
......
}
</pre>
很明显,这里向window添加了mStatusBarView布局,也就是状态栏布局。