Activity -- setContentView
public void setContentView(View view) {
getWindow().setContentView(view);
initWindowDecorActionBar();
}
public Window getWindow() {
return mWindow;
}
final void attach(。。。) {
...
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
}
在Activity的
setContentView
方法中调用了Window对应的方法,Window本身是一个抽象类,这里它的实现类是PhoneWindow,实际上调用的是PhoneWindow的setContentView
方法。
PhoneWindow -- setContentView
ViewGroup mContentParent;
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor(); //注释1
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
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;
}
第一次调用的时候
mContentParent
为null,会执行installDecor()
方法,在该方法中会创建mContentParent
;继续执行下面会把传入的布局添加到mContentParent
中:mLayoutInflater.inflate(layoutResID, mContentParent);
//注释1
private void installDecor() {
...
if (mDecor == null) {
mDecor = generateDecor(-1);
...
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
...
}
}
在
installDecor
方法中,会创建mDecor
(DecorView)和mContentParent
protected DecorView generateDecor(int featureId) {
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, getContext().getResources());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
return new DecorView(context, featureId, this, getAttributes());
}
public class DecorView extends FrameLayout
直接
new DecorView
,DecorView
本质是一个FrameLayout
。
protected ViewGroup generateLayout(DecorView decor) {
......
//根据设置的feature来选择Activity的根部局
int layoutResource;
int features = getLocalFeatures();
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;
}
removeFeature(FEATURE_ACTION_BAR);
}
......
else {
layoutResource = R.layout.screen_simple;
}
mDecor.startChanging();
//往DecorView加载根部局
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
//找到内容布局:不管选择哪个根部局,内容布局id都设置为ID_ANDROID_CONTENT这个参数值
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
return contentParent;
}
public abstract class Window{
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
}
根据
feature
来选择Activity不同的布局,然后将布局添加到mDecor
中,不管是哪种布局,内容的布局id都是ID_ANDROID_CONTENT
,然后获取内容布局赋值给contentParent。
R.layout.screen_simple
<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>
R.layout.screen_simple
添加到DecorView中,DecorView在PhoneWindow中,所以通过findViewById(ID_ANDROID_CON)
获取到的是FrameLayout返回给mContentParent
。通过setContentView
设置布局就是往mContentParent
里面添加内容。它本质是一个FrameLayout。
布局层级图
我们打开一个应用,最外层是一个PhoneWindow,它里层是一个DecorView,本质就是一个FrameLayout,然后它里层是一个LinearLayout,是一个垂直方向的,上面是延时加载的ActionBar,因为Activity可能没有actionBar,所以用ViewStub布局;下面是一个FrameLayout,我们通过
setContentView
设置的布局,就是往该FrameLayout中添加内容。
网友评论