美文网首页
setContentView浅析

setContentView浅析

作者: tf24 | 来源:发表于2018-01-25 15:31 被阅读0次

从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的布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <ViewStub 
         android:id="@+id/action_mode_bar_stub"
         android:inflatedId="@+id/action_mode_bar"
         android:layout="@layout/action_mode_bar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:theme="?attr/actionBarTheme" />
    <FrameLayout
         android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:foregroundInsidePadding="false"
         android:foregroundGravity="fill_horizontal|top"
         android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

此布局包含了actionbar和content

4. mLayoutInflater.inflate(layoutResID, mContentParent);

相当于

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

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

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

activity布局层级.PNG

相关文章

网友评论

      本文标题:setContentView浅析

      本文链接:https://www.haomeiwen.com/subject/ftgmaxtx.html