setContentView() 方法 是Activity中onCreate ()方法的第二行,默认是传入一个R.layout.activity_xxx,目的是将我们在xml中写的布局解析渲染到屏幕上进行显示。
setContentView()流程
setContentView()在继承Activity和AppCompatActivity是不同的,我们先来看Activity中的setContentView()。
1、Activity#setContentView()
MainActivity继承Activity
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
Activity#setContentView()
Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(mWindowControllerCallback);
mWindow.setCallback(this);
...//`省略部分代码`
}
//2、获取Window
public Window getWindow() {
return mWindow;
}
//1、设置xml
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
-
Activity#setContentView()是调用getWindow().setContentView(layoutResID) -
getWindow()方法返回一个Window对象mWindow -
mWindow对象在Activity#attach()方法中实例化,是一个PhoneWindow对象
那么Activity#setContentView(layoutResID)其实就是调用了PhoneWindow#setContentView()
PhoneWindow#setContentView()
PhoneWindow.java
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//代码1
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 {
//代码2
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
PhoneWindow#setContentView()中做了两件事
-
判断
mContentParent为空的时候进入代码1的位置调用方法installDecor() -
执行
代码2将传入的xml加载到mContentParent中
我们设置的xml加载到了mContentParent中,那么我们需要知道mContentParent是怎么创建的
先看installDecor()
private void installDecor() {
mForceDecorInstall = false;
//代码1
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
//代码2
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
..省略部分代码
}
}
protected DecorView generateDecor(int featureId) {
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, this);
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
return new DecorView(context, featureId, this, getAttributes());
}
installDecor()方法
-
代码2mContentParent = generateLayout(mDecor)可以看出是对mContentParent进行初始化。但是传入了一个mDecor,那这个mDecor是什么 -
代码1generateDecor()是对mDecor的初始化,查看方法generateDecor()返回值是一个DecorView对象。
代码2中的方法generateLayout(mDecor)
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
protected ViewGroup generateLayout(DecorView decor) {
...省略部分代码
//代码1
int layoutResource;
int features = getLocalFeatures();
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 ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {
// Special case for a window with only a progress bar (and title).
// XXX Need to have a no-title version of embedded windows.
layoutResource = R.layout.screen_progress;
// System.out.println("Progress!");
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
// Special case for a window with a custom title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_custom_title;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
// If no other features and not embedded, only need a title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
layoutResource = a.getResourceId(
R.styleable.Window_windowActionBarFullscreenDecorLayout,
R.layout.screen_action_bar);
} else {
layoutResource = R.layout.screen_title;
}
// System.out.println("Title!");
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
}
mDecor.startChanging();
//代码2
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
//代码3
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
ProgressBar progress = getCircularProgressBar(false);
if (progress != null) {
progress.setIndeterminate(true);
}
}
// Remaining setup -- of background and title -- that only applies
// to top-level windows.
if (getContainer() == null) {
mDecor.setWindowBackground(mBackgroundDrawable);
final Drawable frame;
if (mFrameResource != 0) {
frame = getContext().getDrawable(mFrameResource);
} else {
frame = null;
}
mDecor.setWindowFrame(frame);
mDecor.setElevation(mElevation);
mDecor.setClipToOutline(mClipToOutline);
if (mTitle != null) {
setTitle(mTitle);
}
if (mTitleColor == 0) {
mTitleColor = mTextColor;
}
setTitleColor(mTitleColor);
}
mDecor.finishChanging();
return contentParent;
}
@Nullable
public <T extends View> T findViewById(@IdRes int id) {
return getDecorView().findViewById(id);
}
@Override
public final @NonNull View getDecorView() {
if (mDecor == null || mForceDecorInstall) {
installDecor();
}
return mDecor;
}
generateLayout(mDecor)方法
-
generateLayout(mDecor)方法最后返回一个contentParent,也就是上面的mContentParent; -
从
70行代码3看到contentParent是通过findViewById查找一个ID_ANDROID_CONTENT值为com.android.internal.R.id.content的一个ViewGroup; -
而
114行的findViewById()可以看到是DecorView#findViewById去查找的。 -
67行代码2处调用mDecor.onResourcesLoaded(mLayoutInflater, layoutResource)传入一个layoutResource; -
第6行代码1及后续代码得知layoutResource是一个int,通过features的判断进行不同xml的赋值,最后通过mDecor.onResourcesLoaded方法将xml设置到DecorView中。
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
mDecorCaptionView = createDecorCaptionView(inflater);
final View root = inflater.inflate(layoutResource, null);
if (mDecorCaptionView != null) {
if (mDecorCaptionView.getParent() == null) {
addView(mDecorCaptionView,
new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mDecorCaptionView.addView(root,
new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
} else {
// Put it below the color views.
addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mContentRoot = (ViewGroup) root;
initializeElevation();
}
随机找两个layoutResource 的赋值xml布局查看
R.layout.screen_title.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
<!-- Popout bar for action modes -->
<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:layout_width="match_parent"
android:layout_height="?android:attr/windowTitleSize"
style="?android:attr/windowTitleBackgroundStyle">
<TextView android:id="@android:id/title"
style="?android:attr/windowTitleStyle"
android:background="@null"
android:fadingEdge="horizontal"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
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>
可以看到两个布局中都有一个id为@android:id/content的FrameLayout,
而上面得知,contentParent是通过findViewById查找一个id为com.android.internal.R.id.content的一个ViewGroup。而这两个id是相等的(笔者不知道原因,有大佬知道可以指导下)。所以contentParent就是这个id为@android:id/content的FrameLayout。
此时得知generateLayout(mDecor)中根据不同的features得不同的xml,并把这个xml加载到mDecor也就是DecorView中,这些xml中有一个id为 @android:id/content 的FrameLayout,而mContentParent就是这个FrameLayout。
回到PhoneWindow#setContentView()
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//代码1
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
...
} else {
//代码2
mLayoutInflater.inflate(layoutResID, mContentParent);
}
}
代码2中将Activity#setContentView()中传入的xml布局,通过mLayoutInflater.inflate(layoutResID, mContentParent)加载到mContentParent中。
总结
-
Activity#setContentView()其实是调用了PhoneWindow#setContentView()方法; -
PhoneWindow#setContentView()方法中调用installDecor()创建DecorView对象mDecor; -
generateLayout(mDecor)根据不同的feature加载不同的xml,将xml添加到DecorView中,获取xml中的id为com.android.internal.R.id.content的FrameLayout(mContentParent)通过LayoutInflater#inflate将传入的布局xml加载到mContentParent中
最后Activity的层级是下图
2、AppCompatActivity#setContentView()
MainActivity继承AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
AppCompatActivity.java
@Override
public void setContentView(@LayoutRes int layoutResID) {
initViewTreeOwners();
getDelegate().setContentView(layoutResID);
}
@NonNull
public AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, this);
}
return mDelegate;
}
AppCompatDelegate.java
@NonNull
public static AppCompatDelegate create(@NonNull Activity activity,
@Nullable AppCompatCallback callback) {
return new AppCompatDelegateImpl(activity, callback);
}
AppCompatActivity#setContentView()
AppCompatActivity#setContentView()方法中调用getDelegate().setContentView(layoutResID),而getDelegate()通过AppCompatDelegate.create(this, this)返回一个AppCompatDelegateImpl对象
那么AppCompatActivity#setContentView()最终会执行到AppCompatDelegateImpl#setContentView()中
AppCompatDelegateImpl.java
@Override
public void setContentView(int resId) {
//代码1
ensureSubDecor();
//代码2
ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
//代码3
LayoutInflater.from(mContext).inflate(resId, contentParent);
mAppCompatWindowCallback.getWrapped().onContentChanged();
}
AppCompatDelegateImpl#setContentView()
-
代码2 contentParent是mSubDecor获取一个android.R.id.content的ViewGroup; -
代码3通过LayoutInflater#inflat()将AppCompatActivity#setContentView()传入的xml加载到contentParent中
根据上面分析Activity#setContentView()的流程,mContentParent是DecorView中的一个id为com.android.internal.R.id.content的FrameLayout,然后将Activity#setContentView()传入的xml布局通过LayoutInflater#inflat加载到mContentParent
两个的处理方式有点异曲同工
那剩下的我们只需要分析代码1即ensureSubDecor()方法
AppCompatDelegateImpl.java
private void ensureSubDecor() {
if (!mSubDecorInstalled) {
//初始化mSubDecor
mSubDecor = createSubDecor();
...省略部分代码
}
}
ensureSubDecor()
ensureSubDecor()方法中通过createSubDecor()创建mSubDecor,继续看createSubDecor()方法
AppCompatDelegateImpl.java
private ViewGroup createSubDecor() {
...省略部分代码
//代码2
ViewGroup subDecor = null;
if (!mWindowNoTitle) {
if (mIsFloating) {
subDecor = (ViewGroup) inflater.inflate(
R.layout.abc_dialog_title_material, null);
...
} else if (mHasActionBar) {
...
subDecor = (ViewGroup) LayoutInflater.from(themedContext)
.inflate(R.layout.abc_screen_toolbar, null);
mDecorContentParent = (DecorContentParent) subDecor
.findViewById(R.id.decor_content_parent);
...
} else {
if (mOverlayActionMode) {
subDecor = (ViewGroup) inflater.inflate(
R.layout.abc_screen_simple_overlay_action_mode, null);
} else {
subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);
}
}
...省略部分代码
return subDecor;
}
createSubDecor()
createSubDecor()方法最后返回一个subDecor对象,而subDecor是根据不同的配置加载的不同xml:
R.layout.abc_dialog_title_material
R.layout.abc_screen_toolbar
R.layout.abc_screen_simple_overlay_action_mode
R.layout.abc_screen_simple
下面是四个xml的布局详情
R.layout.abc_dialog_title_material
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.FitWindowsLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
android:fitsSystemWindows="true">
<TextView
android:id="@+id/title"
style="?android:attr/windowTitleStyle"
android:singleLine="true"
android:ellipsize="end"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:textAlignment="viewStart"
android:paddingLeft="?attr/dialogPreferredPadding"
android:paddingRight="?attr/dialogPreferredPadding"
android:paddingTop="@dimen/abc_dialog_padding_top_material"/>
<include
layout="@layout/abc_screen_content_include"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</androidx.appcompat.widget.FitWindowsLinearLayout>
R.layout.abc_screen_toolbar
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.ActionBarOverlayLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/decor_content_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<include layout="@layout/abc_screen_content_include"/>
<androidx.appcompat.widget.ActionBarContainer
android:id="@+id/action_bar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
style="?attr/actionBarStyle"
android:touchscreenBlocksFocus="true"
android:gravity="top">
<androidx.appcompat.widget.Toolbar
android:id="@+id/action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:navigationContentDescription="@string/abc_action_bar_up_description"
style="?attr/toolbarStyle"/>
<androidx.appcompat.widget.ActionBarContextView
android:id="@+id/action_context_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:theme="?attr/actionModeTheme"
style="?attr/actionModeStyle"/>
</androidx.appcompat.widget.ActionBarContainer>
</androidx.appcompat.widget.ActionBarOverlayLayout>
R.layout.abc_screen_simple_overlay_action_mode
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.FitWindowsFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/action_bar_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<include layout="@layout/abc_screen_content_include" />
<androidx.appcompat.widget.ViewStubCompat
android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/abc_action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.appcompat.widget.FitWindowsFrameLayout>
R.layout.abc_screen_simple
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.FitWindowsLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/action_bar_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:fitsSystemWindows="true">
<androidx.appcompat.widget.ViewStubCompat
android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/abc_action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<include layout="@layout/abc_screen_content_include" />
</androidx.appcompat.widget.FitWindowsLinearLayout>
可以看到所有的xml都有include一个@layout/abc_screen_content_include的xml布局
查看abc_screen_content_include.xml
布局中只有
id为 @id/action_bar_activity_content的ContentFrameLayout
abc_screen_content_include.xml
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.appcompat.widget.ContentFrameLayout
android:id="@id/action_bar_activity_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</merge>
private ViewGroup createSubDecor() {
...省略部分代码
// Now let's make sure that the Window has installed its decor by retrieving it
ensureWindow();
//代码1
mWindow.getDecorView();
final LayoutInflater inflater = LayoutInflater.from(mContext);
//代码2
ViewGroup subDecor = null;
if (!mWindowNoTitle) {
if (mIsFloating) {
subDecor = (ViewGroup) inflater.inflate(
R.layout.abc_dialog_title_material, null);
...
} else if (mHasActionBar) {
...
subDecor = (ViewGroup) LayoutInflater.from(themedContext)
.inflate(R.layout.abc_screen_toolbar, null);
mDecorContentParent = (DecorContentParent) subDecor
.findViewById(R.id.decor_content_parent);
...
} else {
if (mOverlayActionMode) {
subDecor = (ViewGroup) inflater.inflate(
R.layout.abc_screen_simple_overlay_action_mode, null);
} else {
subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);
}
}
...省略部分代码
if (mDecorContentParent == null) {
mTitleView = (TextView) subDecor.findViewById(R.id.title);
}
//代码3
final ContentFrameLayout contentView = (ContentFrameLayout) subDecor.findViewById(
R.id.action_bar_activity_content);
//代码4
final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
if (windowContentView != null) {
// There might be Views already added to the Window's content view so we need to
// migrate them to our content view
//代码5
while (windowContentView.getChildCount() > 0) {
final View child = windowContentView.getChildAt(0);
windowContentView.removeViewAt(0);
contentView.addView(child);
}
// Change our content FrameLayout to use the android.R.id.content id.
// Useful for fragments.
//代码6
windowContentView.setId(View.NO_ID);
contentView.setId(android.R.id.content);
// The decorContent may have a foreground drawable set (windowContentOverlay).
// Remove this as we handle it ourselves
if (windowContentView instanceof FrameLayout) {
((FrameLayout) windowContentView).setForeground(null);
}
}
// Now set the Window's content view with the decor
//代码7
mWindow.setContentView(subDecor);
contentView.setAttachListener(new ContentFrameLayout.OnAttachListener() {
@Override
public void onAttachedFromWindow() {}
@Override
public void onDetachedFromWindow() {
dismissPopups();
}
});
return subDecor;
}
回到createSubDecor()中,为了方便我又复制了一遍源码。
-
代码2的地方声明了subDecor对象,然后解析对应的xml,最后返回。 -
代码3获取一个id为action_bar_activity_content的contentView布局,也就是subDecor对应加载xml布局中的abc_screen_content_include.xml中的id为@id/action_bar_activity_content的ContentFrameLayout。 -
代码4中获取了Window中windowContentView也就是是我们最后加载传入xml的mContentParent,总感觉哪里不对,mContentParent什么时候初始化的,mContentParent有初始化吗?对!!!在代码1中mWindow.getDecorView()调用了installDecorView(),然后初始化了mDecor和mContentParent。
代码5中通过while循环,将windowContentView中的子View全部添加到代码3中contentView中然后在代码6将windowContentView的id设置为-1,contentView设置为android.R.id.content,也就是上面AppCompatDelegateImpl#setContentView()方法中的contentParent
- 当然还有最后
代码7通过mWindow.setContentView(subDecor)将subDecor设置到mWindow的mContentParent中
总结
-
AppCompatActivity#setContentView()最终会执行到AppCompatDelegateImpl#setContentView() -
AppCompatDelegateImpl#setContentView()首先调用ensureSubDecor()方法通过createSubDecor()创建mSubDecor;- 通过
mWindow.getDecorView()初始化DecorView和mContentParent - 根据不同的参数,加载一个包含
@layout/abc_screen_content_include的xml - 获取
mContentParent和abc_screen_content_include中的ContentFrameLayout然后while遍历把mContentParent添加到ContentFrameLayout中,并设置mContentParent的id为View.NO_ID 即-1,设置ContentFrameLayoutid为android.R.id.content - 通过
mWindow.setContentView(mSubDecor)设置给mContentParent
- 通过
-
mSubDecor获取一个id为android.R.id.content的ViewGroup contentParent,通过LayoutInflater#inflat()将传入的xml加载到contentParent中