Activity - setContentView源码分析

1. setContentView源码分析

第一:Activity源码中的setContentView:
    public void setContentView(@LayoutRes int layoutResID) {
        // 获取 getWindow的 setContentView方法,但是setContentView是抽象方法,
        // 需要找 实现类 PhoneWindow
        getWindow().setContentView(layoutResID);
    }

    // mWindow是 PhoneWindow,如下创建系统的 PhoneWindow 对象,说明第一层是 PhoneWindow
    public Window getWindow() {
        return mWindow;
    }

    mWindow = new PhoneWindow(this, window);

所以需要在 PhoneWindow中 查找 setContentView:

    // PhoneWindow的 setContentView
    @Override
    public void setContentView(int layoutResID) {
        // 如果 mContentParent 为空,调用 installDecor()
        if (mContentParent == null) {
            installDecor();
        }
        // 把我们自己的 setContentView 设置到 mContentParent
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
第二:对于installDecor:这里有2个方法:分别是:generateDecor 和 generateLayout
private DecorView mDecor;
private void installDecor() {
    if (mDecor == null) {
        // 第二层:DecorView,创建 DecorView对象
        mDecor = generateDecor(-1);
    }
    if (mContentParent == null) {
        // 第三层:mContentParent,把 setContentView 加载到 mContentParent
        mContentParent = generateLayout(mDecor);
    }

// generateDecor:创建DecorView对象, DecorView 继承 FrameLayout,所以 第二层是 DecorView
protected DecorView generateDecor(int featureId) {
    return new DecorView(context, featureId, this, getAttributes());
}

public class DecorView extends FrameLayout implements RootViewSurfaceTaker{}

protected ViewGroup generateLayout(DecorView decor) {
    int layoutResource;
    // 通过一系列的 if...else... 判断,最终会调用到 R.layout.screen_simple,说明它是第三层
    // 它的最外层是 LinearLayout,
    layoutResource = R.layout.screen_simple;
    // 把 screen_simple 布局文件添加到 DecorView
    mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

    // ID_ANDROID_CONTENT:是screen_simple布局文件中的 一个 控件,是 FrameLayout,
    // id 为 android.R.id.content,这个 id 把 我们的 setContentView 加载到 mContentParent 中
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    // 返回
    return contentParent;
}

对于 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" />

    // android.R.id.content
    <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>

2 总结

1>:Activity中调用 setContentView,布局显示在 PhoneWindow中,在PhoneWindow中实例化 DecorView;
2>:然后 做一系列判断,解析系统资源文件,把 android.R.layout.screen_simple 加载到 DecorView中,screen_simple布局文件最外层是一个 LinearLayout,里边有一个 id是 android.R.id.content,是一个 FrameLayout;
3>:我们自己的 setContentView 布局文件 加载到 mContentParent中,就是 android.R.id.content 的 FrameLayout;

《Activity - setContentView源码分析》 图片.png

    原文作者:世道无情
    原文地址: https://www.jianshu.com/p/da56c4de3050
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞