setContentView浅析

从PhoneWindow到用户最终设定的contentView,一共有4个层级

  • PhoneWindow
    • (层级1)DecorView
      • (层级2)layout : 通过activity传递的参数来选择出LayoutID,并添加到DecorView中,该layout中包含actionbar,content等
        • ViewStub : ActionBar
        • (层级3)FrameLayout mContentParent : @android:id/content,作为content的父容器
          • (层级4)content : 就是用户setContentView设置的activity视图
备注:可以从AndroidStudio Layout Inspector中查看层级

源码解析

1. 首先Activity的setContentView

public void setContentView(@LayoutRes int layoutResID) {
    // getWindow()返回mWindow成员变量,在attach方法中初始化为一个PhoneWindow的对象
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

2. 继续来看PhoneWindow的setContentView方法

    public void setContentView(int layoutResID) {
        // 省略部分代码
        installDecor();
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }

3. 看installDecor()方法

private void installDecor() {
    if (mDecor == null) {
        // 实例化mDecorView
        mDecor = generateDecor(-1);
    }
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);
    }
}
mDecor是PhoneWindow的一个成员变量,类型是DecorView,关于mDecorView的注释如下
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;

可以看出mDecor是PhoneWindow最顶层的View,也就是根View
generateDecor方法比较简单,就是构造一个DecorView的实例

mContentParent也是PhoneWindow的一个成员变量,类型是ViewGroup
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;

是说mContentParent是窗口内容视图的容器,它可能是mDecor本身,也可能是mDecor的一个子视图

protected ViewGroup generateLayout(DecorView decor) {
    // 此处首先解析用户设定主题window属性,然后根据这些属性选择合适的layout加载到mDecor中
    // Inflate the window decor.
    int layoutResource;
    // 只列举一个布局作为示例
    layoutResource = R.layout.screen_simple;
    mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    return contentParent;
}

此段代码中,首先会去解析应用设定的窗口属性(代码太多没有写出来),然后根据这些属性选择合适的布局layout,将该layout加载出来并添加到mDecor中,在mDecor.onResourcesLoaded中实现,然后返回layout中id为ID_ANDROID_CONTENT(com.android.internal.R.id.content)的视图,返回作为mContentParent

来看screen_simple的布局:

    
    

此布局包含了actionbar和content

4. mLayoutInflater.inflate(layoutResID, mContentParent);

相当于

View content = mLayoutInflater.inflate(layoutResID, null);
mContentParent.addView(content);

将用户传入的activity layout添加到mContentParent之中。

至此,setContentView大概过程已经结束,activity对应的窗口布局层级也应该很清楚了,大致可用下图表示:

setContentView浅析_第1张图片
activity布局层级.PNG

你可能感兴趣的:(setContentView浅析)