首先进入activity中找到setContentView方法:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
找到三个setContentView方法,我们发现内部都是调用getWindow()的setContentView方法,getWindow()得到一个在Activity的attach方法中初始化的PhoneWindow对象mWindow
进入PhoneWindow类可知,该类继承Window类,Window类是抽象类,注释如下
/**
* Abstract base class for a top-level window look and behavior policy. An
* instance of this class should be used as the top-level view added to the
* window manager. It provides standard UI policies such as a background, title
* area, default key processing, etc.
*
* <p>The only existing implementation of this abstract class is
* android.view.PhoneWindow, which you should instantiate when needing a
* Window.
*/
public class PhoneWindow extends Window implements MenuBuilder.Callback {
百度翻译:顶级视图和行为策略的基础抽象类。此类的实例被用做顶级视图添加到window manager中。提供了UI策略规则,如背景background、title区域、默认key处理等
该抽象类存在的唯一的实现是android.view.PhoneWindow,当你需要一个window的时候可以用到它。
每个Activity持有一个Window对象,也就是PhoneWindow,PhoneWindow又持有了一个DecorView对象,DecorView对象所加载的布局资源中含有TextView(R.id.title)和FrameLayout(R.id.content)
回到PhoneWindow中,找到setContentView方法
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
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 {
//将layoutResID解析后添加到mContentParent的子view树里
mLayoutInflater.inflate(layoutResID, mContentParent);
}
...
...
...
}
首先来看mContentParent
ViewGroup mContentParent;
mContentParent 是被放置在window窗口的视图,可能是mDecor 本身,或者是mDecor 的子视图
private DecorView mDecor;
DecorView 是window窗口顶级视图,包含窗口装饰
当mContentParent == null时执行installDecor()方法
private void installDecor() {
...
if (mDecor == null) {
//不存在,创建
mDecor = generateDecor(-1);
...
} else {
//存在,将此PhoneWindow传递给mDecor
mDecor.setWindow(this);
}
if (mContentParent == null) {
//创建基础试图框架mContentParent ,并在其中为mDecor设置布局资源
mContentParent = generateLayout(mDecor);
...
//decor_content_parent是基础布局中最外层布局的id,其中的根布局ActionBarOverlayLayout
//实现了DecorContentParent 接口
final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
R.id.decor_content_parent);
if (decorContentParent != null) {
mDecorContentParent = decorContentParent;
//设置Window的一些回调、title等
mDecorContentParent.setWindowCallback(getCallback());
...
...
...
} else {
//设置title,根据FEATURE_NO_TITLE设置是否显示
mTitleView = findViewById(R.id.title);
if (mTitleView != null) {
if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
final View titleContainer = findViewById(R.id.title_container);
if (titleContainer != null) {
titleContainer.setVisibility(View.GONE);
} else {
mTitleView.setVisibility(View.GONE);
}
mContentParent.setForeground(null);
} else {
mTitleView.setText(mTitle);
}
}
}
if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
mDecor.setBackgroundFallback(mBackgroundFallbackResource);
}
...........
}
现在可知installDecor方法的作用有两点:
一、将PhoneWindow绑定给DecorView;
二、调用generateLayout方法.
protected DecorView generateLayout(DecorView decor) {
...
...
//根据activity是否设置ActionBar,为layoutResource赋值不同布局screen_action_bar或者screen_title
//screen_action_bar内部包含R.id.content(Framelayout)和一个ActionBarContainer布局
//screen_title内部包含R.id.content(Framelayout)和一个被Framelayout包裹的R.id.title(TextView)
} 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;
}
...
...
//为mDecor加载布局资源layoutResource
mDecor.startChanging();
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
//contentParent 获取该布局中的R.id.conten(FrameLayout)
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
...
...
//将mDecor布局中的R.id.conten(FrameLayout)作为基础布局框架返回
return contentParent;
}
generateLayout方法的主要作用
1、创建基础视图框架布局mContentParent ;
2、对mDecor加载资源布局。
其中mContentParent 是mDecor布局中的子view(R.id.content)
在setContentView方法中执行完installDecor方法后会执行mLayoutInflater.inflate(layoutResID, mContentParent);将传递进来的layoutResID布局资源解析添加到mContentParent (com.android.internal.R.id.content)的子view树里,到这里就完成了setContentView方法的布局加载。