Activity 的 setContentView 做了什么

开门见山,Activity 的 setContentView 方法里面调用了 PhoneWindow 的同名方法。

//Activity 的 setContentView 调用的其实是 PhoneWindow 的 setContentView
//PhoneWindow
public void setContentView(int layoutResID) {
    //源码注释说,mContentParent 是用来展示窗口内容的,也就是我们看到的屏幕内容
    //它的值可以是 mDecor 也可以是 mDecor 包含内容的子 view。
    //所以说我们创建的 Activity 能展示出来,关键要看它
    if (mContentParent == null) {
        //先假设进到这里,看上去是去创建 DecorView
        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 {
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
}

方法大致分三部分,第一部分是准备好容器,第二部分是解析布局(就是我们入参传进来的),第三部分我想着应该渲染布局了,但是看了下好像没有走到,可能是我看的不对,第三部分要再看看。来说说前两部分,

private void installDecor() {
    //这个 mDecor 就是 DecorView 类型
    //简单来说就是 mDecor 要是为 null 就创建,并关联当前 PhoneWindow 对象
    //要是不为 null 就直接关联当前 PhoneWindow 对象
    if (mDecor == null) {
        mDecor = generateDecor(-1);
    } else {
        mDecor.setWindow(this);
    }
    if (mContentParent == null) {
        //创建完 mDecor 后再来创建 mContentParent
        //generateLayout 方法里做了很多工作,大体上看是个主题样式相关的,沉浸式通知栏,还有标题都是在这里确定的。
        //还有系统定义的 R.id.content 这个布局控件就是 mContentParent
        //而 R.id.content 就是 DecorView 上的一个布局
        mContentParent = generateLayout(mDecor);
        //findViewById 是 Window 的方法,最终会调用 View 的 findViewById 方法,这里也就是从 DecorView 中找 id 为 title 的控件
        mTitleView = findViewById(R.id.title);
    }
}

容器有两个内容,mDecor 是 DecorView 类型的,包括两部分布局,一个是 title, 一个是 content。mContentParent 是 ViewGroup 类型,对应的就是 mDecor 的 content 部分。

public void setContentView(int layoutResID) {
    //这个条件看去像是说窗口内容变换是否要用 TransitionManager 做个动画效果,没特殊需求都是不需要的,我们走 else
    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {} 
    else {
        //mLayoutInflater 会在 PhoneWindow 创建时创建
        //inflate 方法平时也比较常见,基本上就是加载 xml 布局文件了
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
}
//resource 就是 xml 布局文件索引
//root 就是 xml 生成的 View 视图树的父亲,方法注释说,如果 root 有值,那么 root 就是方法返回的那个 view。如果 root 为 null,那么方法返回的 View 就是 xml 布局文件的根节点。也就是说如果 xml 布局里的根布局是个线性布局 LinearLayout,那么方法返回的 View 就是这个 LinearLayout
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    return inflate(resource, root, root != null);
}

xml 解析过程就是将我们为 Activity 设计的布局,映射到 mContentparent 上。

至于 setContentView 剩下的代码,我简单看了下,并没有做更多的事情,待我找时间再仔细梳理。

你可能感兴趣的:(Activity 的 setContentView 做了什么)