上篇文章追溯了Android源码中Activity的启动流程,那么Activity启动之后,是如何加载布局的呢?这篇文章我们继续来追溯这一块的Android源码。
Activity->setContentView
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
这里调用了Window的setContentView方法,而Window是一个抽象类,PhoneWindow是其唯一派生子类,所以这里调用的是PhoneWindow中的setContentView方法。
PhoneWindow->setContentView
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {// TAG1
//创建DecorView,并添加到mContentParent上
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
//将布局加载到mContentParent上
mLayoutInflater.inflate(layoutResID, mContentParent);/// TAG2
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
//回调通知界面加载完毕
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
首先看标识TAG1处,这里判断mContentParent是否为空,后面我们可以知道这个mContentParent表示的是DecorView中展示内容的布局(除去标题栏)。到这一步,我们还没有创建过DecorView,也就更不可能生成mContentParent了,所以这里的判断是为true的。也就是会执行installDecor()方法。
Activity->installDecor
private void installDecor() {
mForceDecorInstall = false;
/ TAG3
if (mDecor == null) {
//如果mDecor为空,创建一个DecorView赋给mDecor
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
/ TAG4
if (mContentParent == null) {
//根据主题以及设置的FEATURE为mDecor添加默认布局
mContentParent = generateLayout(mDecor);
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
mDecor.makeOptionalFitsSystemWindows();
final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
R.id.decor_content_parent);
//添加其他资源
......
//设置转场动画
if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
......
}
}
}
TAG3处没什么好说的,就是创建一个DecorView赋给mDecor。
这里我们重点看TAG4处新建mContentParent的过程,调用的是generateLayout(mDecor)方法。
PhoneWindow->generateLayout(DecorView decor)
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
//获取当前设置的窗口主题
//这也就是为什么我们要在setContentView之前调用requesetFeature的原因
TypedArray a = getWindowStyle();
......//根据设置加载默认主题
// Inflate the window decor.
int layoutResource;
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
// 根据用户设置的Feature来设置DecorView的布局资源
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;
setCloseOnSwipeEnabled(true);
} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_title_icons;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
// System.out.println("Title Icons!");
} else if ......一系列的判断
mDecor.startChanging();
//将符合配置的布局创建并添加到DecorVie