Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >View 源码分析——setContentView

View 源码分析——setContentView

原创
作者头像
CatEatFish
修改于 2020-07-09 06:21:20
修改于 2020-07-09 06:21:20
5440
举报
文章被收录于专栏:干活分享干活分享

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

  • 分析onCreate中的setContentView:
代码语言:txt
AI代码解释
复制
// 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是什么?等会解释)

代码语言:txt
AI代码解释
复制
// 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

代码语言:txt
AI代码解释
复制
  // 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 呢?

代码语言:txt
AI代码解释
复制
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的布局

代码语言:txt
AI代码解释
复制
//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
    系统布局.png

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

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android 源码解析 之 setContentView「建议收藏」
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41894125,本文出自:【张鸿洋的博客】
全栈程序员站长
2022/09/13
3520
Activity中setContentView过程
可以看见上面方法主要作用就是根据窗口的风格修饰类型为该窗口选择不同的窗口根布局文件。mDecor做为根视图将该窗口根布局添加进去,然后获取id为content的FrameLayout返回给mContentParent对象。所以installDecor方法实质就是产生mDecor和mContentParent对象。另一方面如果要设置窗口风格,必须放在setContentView的前面:
全栈程序员站长
2022/09/13
2770
setContentView流程
activity是Android的四大组件之一,负责控制activity的生命周期和处理事件,负责视图的添加与显示,以及通过一些回调方法与window和View进行交互。一个activity包含一个window,window才是真正的窗口
全栈程序员站长
2022/09/13
5820
Window源码解析(一):与DecorView的那些事
注:本文解析的源码基于 API 25,部分内容来自于《Android开发艺术探索》。
俞其荣
2022/07/28
5770
Window源码解析(一):与DecorView的那些事
Android界面启动流程(一)
目的:深入分析setContentView方法传入布局文件id,到底做了什么 setContentView方法内部: public void setContentView(@LayoutRes int layoutResID) { getWindow().setContentView(layoutResID); initWindowDecorActionBar(); } 调用了getWindow()的setContentView方法 public Wi
aruba
2020/07/03
9810
Android界面启动流程(一)
AppCompatActivity.setContentView如何装载视图到AppCompatActivity上
注意:AppCompatActivity.setContentView()与Activity.setContentView()主要的区别,Activity.setContentView直接将视图添加到Window上,AppCompatActivity.setContentView()借助AppCompatActivity的Delegate代理类,将要显示的视图加入到代理层视图,代理层视图在添加到Window上;
全栈程序员站长
2022/09/13
5270
Android应用setContentView与LayoutInflater加载解析机制源码分析
【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果】
全栈程序员站长
2022/09/13
4810
关于setContentView方法
我们直接看看 Activity 的三个 setContentView 方法的源码:
103style
2022/12/19
4530
关于setContentView方法
自定义View(七)-View的工作原理- Activity的布局加载
前面几篇对动画可以说是做了非常全面的总结了(上篇文章最后的4种ViewGroup相关动画相信在了解基础后看些文章也不会太难理解)。在View的工作原理 这一部分我们将对View做全面深入的解析。由于本人是菜鸟,其实无法直接看源码,也都是通过书籍与文章反复阅读,然后才去看的源码。由于怕忘记写成博客。希望和我一样不了解的朋友能在自定义View中不那么迷茫。如果那里有错误大家一定指出我将不胜感激。
g小志
2018/09/11
8890
自定义View(七)-View的工作原理- Activity的布局加载
Activity中setContentView浅析
Activity会调用当前Activity的Window的setContentView()方法,而Window类是一个抽象类,唯一实现类PhoneWindow。
全栈程序员站长
2022/09/13
2020
源码分析 | 布局文件加载流程
setContentView 方法如下所示,调用的是 window 中的 setContentView,但是 window 中的只是一个抽象方法:
345
2022/02/11
4830
源码分析 | 布局文件加载流程
Android setContentView流程[通俗易懂]
创建View,当 mFactory2 不为空,就用 factory2 来创建view,否则就返回 view为null
全栈程序员站长
2022/09/13
8010
setContentView的时候,到底发生了什么
关于setContentView方法,想必大家对这个方法既熟悉又陌生,熟悉的原因是因为基本上我们每创建一个activity,都会调用这个方法,比如:
全栈程序员站长
2022/09/13
3380
setContentView源码分析[通俗易懂]
所以最后调用的是 AppCompatDelegateImpl 中的 setContentView
全栈程序员站长
2022/09/13
6160
Activity 启动过程的简单分析
我们都知道,Activity 是有生命周期的,onCreate()、onStart() 、onResume 等等那么这些方法是如何调用的呢?它不会平白无故的自己调用。其实当我们开启 APP 的时候会创建一个叫做 ActivityThread 的类,我们可以认为这个类是主类,就和 Java 程序中的启动类一样,ActivityThread 类有一个 main 函数,这个函数就是我们的程序入口!
开发者
2019/12/26
4760
Activity 启动过程的简单分析
Android 通过DecorView计算statusBar、navigationBar的高度
近期在做项目的时候碰到了底部虚拟按键在各个厂商适配的问题,闷逼了一圈,后面搜索一圈,发现即使各大厂商有变动,还是离不开原生本质
包子388321
2020/06/16
2K0
Android setContentView源码解析
Android开发的同学们对setContentView肯定都不陌生,但凡写到Activity,都离不开这个函数,今天我们就来看看它内部的实现吧!
用户2898788
2018/08/21
9790
Android setContentView()源码流程分析
我们在Activity创建的时候,都用调用setContentView()函数来设置界面,下面我们通过源码来分析setContentView()的流程。 我们先看Activity里面的setContentView进去查看:
曾大稳
2018/09/11
9200
Android setContentView()源码流程分析
长谈:关于 View Measure 测量机制,让我一次把话说完
首先声明,这一篇篇幅很长很长很长的文章。目的就是为了把 Android 中关于 View 测量的机制一次性说清楚。算是自己对自己较真。写的时候花了好几天,几次想放弃,想放弃的原因不是我自己没有弄清楚,而是觉得自己叙事脉络已经紊乱了,感觉无法让读者整明白,怕把读者带到沟里面去,怕自己让人觉得罗嗦废话。但最后,我决定还是坚持下去,因为在反复纠结 –> 不甘 –> 探索 –> 论证 –> 质疑的过程循环中,我完成了对自己的升华,弄明白长久以来的一些困惑。所以,此文最大的目的是给自己作为一些学习记录,如果有幸帮助你解决一些困惑,那么我心宽慰。如果有错的地方,也欢迎指出批评。
Frank909
2019/01/14
7650
Android View源码解读:浅谈DecorView与ViewRootImpl
对于Android开发者来说,View无疑是开发中经常接触的,包括它的事件分发机制、测量、布局、绘制流程等,如果要自定义一个View,那么应该对以上流程有所了解、研究。本系列文章将会为大家带来View的工作流程详细解析。在深入接触View的测量、布局、绘制这三个流程之前,我们从Activity入手,看看从Activity创建后到View的正式工作之前,所要经历的步骤。以下源码均取自Android API 21。
Android技术干货分享
2019/08/22
7250
Android View源码解读:浅谈DecorView与ViewRootImpl
相关推荐
Android 源码解析 之 setContentView「建议收藏」
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档