Activity的setContentView的加载流程分析

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加载流程图如下:

Activity的setContentView的加载流程分析_第1张图片
setContentView加载流程.png

以下是分析流程:

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的加载流程

你可能感兴趣的:(Activity的setContentView的加载流程分析)