专栏首页干活分享View 源码分析——setContentView
原创

View 源码分析——setContentView

分析一下 android 中布局的加载流程,每次新建 activity 时都要在 onCreate 中调用 setContentView(R.layout.activity_main);调用这个方法具体做了哪些事情呢?

  • 分析onCreate中的setContentView:
// mainActivity中
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        }

跳转setContentView()方法,

需要关注的地方有两个:

1、 installDecor(); 用来初始化DecorView

2、 mLayoutInflater.inflate(layoutResID, mContentParent); 将自己的布局添加到mContentParent(mContentParent是什么?等会解释)

// PhoneWindow.java 中
  public void setContentView(int layoutResID) {
       // 刚初始化 mContentParent ==null
        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 {
            // 此处inflate自己布局并且添加到mContentParent布局中
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
      //  .....省略不重要的
    }

看看installDecor()方法中做了什么

1、创建 DecorView

2、构建 mContentParent

  // PhoneWindow中
private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            // 1、创建 DecorView
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
          //如果创建了 则与当前的 window 对象绑定
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            //  2、构建 mContentParent 
            mContentParent = generateLayout(mDecor);
         }
    }

具体是如何创建 mContentParent 呢?

protected ViewGroup generateLayout(DecorView decor) {

        // 系统资源id
        int layoutResource;
        int features = getLocalFeatures();

        // 这些 if else 判断是为了选择加载系统哪个布局的(只截取了一部分)
        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
            layoutResource = R.layout.screen_swipe_dismiss;
            setCloseOnSwipeEnabled(true);
        } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogTitleIconsDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else {
                layoutResource = R.layout.screen_title_icons;
            }
            // XXX Remove this once action bar supports these features.
            removeFeature(FEATURE_ACTION_BAR);
            // System.out.println("Title Icons!");
        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
            // Special case for a window with only a progress bar (and title).
            // XXX Need to have a no-title version of embedded windows.
            layoutResource = R.layout.screen_progress;
            // System.out.println("Progress!");
        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
            // Special case for a window with a custom title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) { .......}

        // mDecor要改变的标记位
        mDecor.startChanging();
        // 它将 layoutResource 布局文件解析成 View 添加到了 DecorView 之中
        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
        // findViewById 找到添加的布局作为父布局contentParent 
       ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
       ......
      // 将此 contentParent 返回 
     return contentParent;
  }

下面看几个R.layout.screen_simple的布局

//layoutResource = R.layout.screen_title_icons;

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:fitsSystemWindows="true"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- Popout bar for action modes -->
    <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"/>
    <RelativeLayout android:id="@android:id/title_container"
        style="?android:attr/windowTitleBackgroundStyle"
        android:layout_width="match_parent"
        android:layout_height="?android:attr/windowTitleSize">
        <!-- The title background has 9px left padding. -->
        <ImageView android:id="@android:id/left_icon"
            android:visibility="gone"
            android:layout_marginEnd="9dip"
            android:layout_width="16dip"
            android:layout_height="16dip"
            android:scaleType="fitCenter"
            android:layout_alignParentStart="true"
            android:layout_centerVertical="true" />
        <ProgressBar android:id="@+id/progress_circular"
            style="?android:attr/progressBarStyleSmallTitle"
            android:visibility="gone"
            android:max="10000"
            android:layout_centerVertical="true"
            android:layout_alignParentEnd="true"
            android:layout_marginStart="6dip"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <!-- There are 6dip between this and the circular progress on the right, we
             also make 6dip (with the -3dip margin_left) to the icon on the left or
             the screen left edge if no icon. This also places our left edge 3dip to
             the left of the title text left edge. -->
        <ProgressBar android:id="@+id/progress_horizontal"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="-3dip"
            android:layout_toStartOf="@android:id/progress_circular"
            android:layout_toEndOf="@android:id/left_icon"
            android:layout_centerVertical="true"
            android:visibility="gone"
            android:max="10000" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            android:layout_toStartOf="@id/progress_circular"
            android:layout_toEndOf="@android:id/left_icon"
            >
            <TextView android:id="@android:id/title"
                style="?android:attr/windowTitleStyle"
                android:layout_width="0dip"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:background="@null"
                android:fadingEdge="horizontal"
                android:scrollHorizontally="true"
                android:gravity="center_vertical"
                android:layout_marginEnd="2dip"
                />
            <!-- 2dip between the icon and the title text, if icon is present. -->
            <ImageView android:id="@android:id/right_icon"
                android:visibility="gone"
                android:layout_width="16dip"
                android:layout_height="16dip"
                android:layout_weight="0"
                android:layout_gravity="center_vertical"
                android:scaleType="fitCenter"
                />
            </LinearLayout>
    </RelativeLayout>
    <FrameLayout android:id="@android:id/content"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foregroundGravity="fill_horizontal|top"
        android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>


// layoutResource = R.layout.screen_title;
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:fitsSystemWindows="true">
    <!-- Popout bar for action modes -->
    <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:layout_width="match_parent" 
        android:layout_height="?android:attr/windowTitleSize"
        style="?android:attr/windowTitleBackgroundStyle">
        <TextView android:id="@android:id/title" 
            style="?android:attr/windowTitleStyle"
            android:background="@null"
            android:fadingEdge="horizontal"
            android:gravity="center_vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
    <FrameLayout android:id="@android:id/content"
        android:layout_width="match_parent" 
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foregroundGravity="fill_horizontal|top"
        android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

// 可以看出每个布局中都有一个被LinearLayout 包裹的 id为 id="@android:id/content" 的FrameLayout 控件
  • 至此可以看出 setContentView 的大体流程来
  • 在Activity生命周期attach方法里面创建出PhoneWindow
  • 调用PhoneWindow的setContentView方法
  • 在PhoneWindow里面创建DecorView,DecorView会去加载系统的一个布局(FrameLayout)
  • 将页面自己写的布局填充到DecorView布局里面id为R.id.content的View,也就是FrameLayout里面
  • View层级图
    系统布局.png

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android快速集成融云

    1、IMKit 集成了会话界面,并且提供了丰富的自定义功能,我们推荐首次接触融云的客户直接使用 IMKit 来快速集成和开发。

    CatEatFish
  • 《Flutter —语法》

    CatEatFish
  • AndroidStudio创建 implementation 依赖

    我们在AndroidStudio中经常使用implementation 的方式来导入第三方代码,比如

    CatEatFish
  • Android 滑动渐变背景Toolbar、点击置顶ScrollView

    这个置顶是滑动的置顶,不包括外层布局。 好了,效果图看到了,你有没有动力开始写代码呢? 创建一个SlideLayoutDemo的项目 然后在res下新建一...

    晨曦_LLW
  • achartengine之折线图

    问题在文章的最后,大致说来就是折线图,如果点的个数大于3个的时候,不是所有的点都显示对应的值的,这是为什么呢,本来以为是小问题,但两天了还没找到原因) 将前...

    xiangzhihong
  • Android XRecyclerView实现多条目加载

    本文实例为大家分享了Android实现多条目加载展示的具体代码,供大家参考,具体内容如下

    砸漏
  • Android颜色配置器配置方法

    想设置颜色直接设置background的属性或者其他的color属性。随便设置一个颜色如#000,再点击左边的颜色方块,弹出颜色选择器选择颜色

    砸漏
  • Android开发实现Files文件读取解析功能示例

    本文实例讲述了Android开发实现Files文件读取解析功能。分享给大家供大家参考,具体如下:

    砸漏
  • Android使用RecyclerView仿美团分类界面

    RecyclerView目前来说对大家可能不陌生了。由于在公司的项目中,我们一直用的listview和gridview。某天产品设计仿照美团的分类界面设计了一个...

    砸漏
  • Android实现简单的城市列表功能

    砸漏

扫码关注云+社区

领取腾讯云代金券