我们在设置自己activity的界面时,通常在onCreate里调用setContentView($layoutId)来达到设置布局的目的。
调用的父类Activity的该方法,如下:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
getWindow()返回的是mWindow,mWindow初始化是在attach方法中,
mWindow = new PhoneWindow(this, window, activityConfigCallback);
跟踪到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.
//mContentParent是我们自己的activity界面布局的父布局,后面会讲到,这里初始化时为空,执
//行installDecor();
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
//这里是判断界面是否有转场动画,最终会把布局id为layoutResID即我们的布局加载到mContentParent中
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
继续看installDecor方法,
private void installDecor() {
mForceDecorInstall = false;
//初始化是mDecor为空,执行generateDecor方法创建DecorView
//generateDecor的返回:return new DecorView(context, featureId, this,
// getAttributes());
//其中DecorView extends FrameLayout
}
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
//将DecorView和Window进行绑定,互相持有对方实例
mDecor.setWindow(this);
}
if (mContentParent == null) {
//这里就是上面提到的我们自己布局所在的父布局
mContentParent = generateLayout(mDecor);
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
mDecor.makeOptionalFitsSystemWindows();
//....省略代码
}
}
继续看generateLayout方法,
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
TypedArray a = getWindowStyle();
//...省略代码
// Inflate the window decor.
//这里加载我们app的整个根布局,也就是DecorView
int layoutResource;
int features = getLocalFeatures();
//省略代码
else{
//默认走的这个分支,所以根部局是layout为screen_simple.xml的文件
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
}
mDecor.startChanging();
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
//在screen_simple.xml的布局里,有一个id为ID_ANDROID_CONTENT即“content"的控件,
//是一个FrameLayout,我们的layout就是通过
//mLayoutInflater.inflate(layoutResId,mContentParent)加载到这里面的
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
//省略代码
//这里把contentParent返回了,赋值给PhoneWindow的mContentParent了
return contentParent;
}
附上screen_simple.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>