1. 概述
这节课我们就来分析下setContentView的源码,首先我会带着大家去看下源码,然后去画一个流程图,最后会去总结下setContentView的加载流程。
2. 分析
Activity的部分源码如下,在Activity源码中直接搜索setContentView():
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
点击getWindow().setContentView(layoutResID);中的 setContentView()发现里边是抽象类,所以这个时候就需要去找它的实现类,所以就去点击 getWindow(),可以发现:
public Window getWindow() {
return mWindow;
}
针对于这种需要去从它的实现类中找源码的,就Ctrl + F 搜索 "变量 = " ,这里就直接搜索 mWindow = ,可以发现是一个该Window是一个 PhoneWindow:
mWindow = new PhoneWindow(this);
然后就找到 PhoneWindow里边的 setContentView()方法,发现 installDecor()方法:
@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) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
}
然后点击installDecor()方法进去,发现generateDecor()方法,然后点击进去发现generateDecor()方法:
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
}
发现generateDecor()方法里边其实就是 new DecorView(getContext(), -1),并且发现该 DecorView是一个内部类,而且是继承 FrameLayout
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker
然后点击 generateLayout(mDecor)方法进去发现在上边经过一系列的if else 判断后最后会调用
else {
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
}
而screen_simple的布局文件如下,可以发现这个布局文件的 根布局是一个 LinearLayout:
这个就是把我们自己的 setContentView()的布局加载到 mContentParent中
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
以上就是setContentView()的源码分析
流程如下:
1>:点击Activity源码中的setContentView(),发现是一个抽象类,这个时候就需要点击 看下mWindow,这个是PhoneWindow实例化的,是系统new PhoneWindow()的,说明最外层是PhoneWindow;
2>:这个时候就需要在 PhoneWindow中查看 setContentView(),里边有 installDecor()方法,点击进去有一个generateDecor() 和 generateLayout()方法;
3>:点击generateDecor()方法进去,系统是new DecorView(),且DecorView类继承FrameLayout,所以DecorView实际是一个FrameLayout,说明第二层是DecorView;
4>:然后继续点击 generateLayout()方法,可以发现在经过一系列的if else判断,最后会调用 android.R.layout.screen_simple,这个布局文件根布局是一个LinearLayout,在这里边一般会去做一系列的判断,比如是否加载头部等等,说明第三层是android.R.layout.screen_simple;
5>:并且这个布局文件中有一个id叫做 android.R.id.content,它是一个FrameLayout,这个android.R.id.content会把我们自己的 setContentView(R.layout.activity_main)加载到 mContentParent中;
这个就是setContentView()的加载流程,可以直接看这个,不需要看下边的;
3. setContentView加载流程图如下:
以下是分析流程:
1>:首先系统会去new PhoneWindow(),然后系统会去new DecorView(),并且这个DecorView是一个 FrameLayout;
2>:然后DecorView会去加载系统的一个资源文件,叫做 android.R.layout.screen_simple,它根布局是一个LinearLayout,然后在这个资源中会去做一系列的 判断,比如是否加载头部,等等;
3>:然后这个资源文件 android.R.layout.screen_simple中有一个 id叫做 android.R.id.content,它是一个FrameLayout,这个android.R.id.content会把我们自己的 setContentView(R.layout.activity_main)加载到 mContentParent中;
以上就是我们的setContentView的加载流程