最简单的Activity中的内容大致是这样的:

public classMainActivity extends Activity {  @Overridepublic voidonCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.main_activity);  }  }

setContentView

一般来说我们设置页面的内容视图是都是通过setContentView方法,那么我们就以2.3源码为例就来看看Activity中的setContentView到底做了什么吧。

1 /**2 * Set the activity content from a layout resource.  The resource will be3 * inflated, adding all top-level views to the activity.4 *5 * @param layoutResID Resource ID to be inflated.6  */
7 public void setContentView(intlayoutResID) {8 getWindow().setContentView(layoutResID);9 }10
11 publicWindow getWindow() {12     returnmWindow;13 }14
15
16 private Window mWindow;  

我们可以看到,实际上调用的mWindow的setContentView方法,在Android Touch事件分发过程这篇文章中我们已经指出Window的实现类为PhoneWindow类

1 @Override2 public void setContentView(intlayoutResID) {3     if (mContentParent == null) {4         installDecor();         //1、生成DecorView
5     } else{6 mContentParent.removeAllViews();7 }8     mLayoutInflater.inflate(layoutResID, mContentParent);//2、将layoutResId的布局添加到mContentParent中
9     final Callback cb =getCallback();10     if (cb != null) {11 cb.onContentChanged();12 }13 }14     //构建mDecor对象,并且初始化标题栏和Content Parent(我们要显示的内容区域)
15     private voidinstallDecor() {16     if (mDecor == null) {17         mDecor = generateDecor();          //3、构建DecorView
18 mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);19         mDecor.setIsRootNamespace(true);20 }21     if (mContentParent == null) {22         mContentParent = generateLayout(mDecor);              //4、获取ContentView容器,即显示内容的区域
23
24         mTitleView = (TextView)findViewById(com.android.internal.R.id.title); 5、设置Title等25         if (mTitleView != null) {26             if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {27                 View titleContainer = findViewById(com.android.internal.R.id.title_container);28                 if (titleContainer != null) {29 titleContainer.setVisibility(View.GONE);30                 } else{31 mTitleView.setVisibility(View.GONE);32 }33                 if(mContentParent instanceof FrameLayout) {34                     ((FrameLayout)mContentParent).setForeground(null);35 }36             } else{37 mTitleView.setText(mTitle);38 }39 }40 }41 }42
43     protectedDecorView generateDecor() {44     return new DecorView(getContext(), -1);    //构建mDecor对象
45 }  

我们可以看到,setContentView的基本流程简单概括就是如下几步:

1、构建mDecor对象。mDecor就是整个窗口的顶层视图,它主要包含了Title和Content View两个区域 (参考图1中的两个区域 ),Title区域就是我们的标题栏,Content View区域就是显示我们xml布局内容中的区域。关于mDecor对象更多说明也请参考Android Touch事件分发过程这篇文章;

2、设置一些关于窗口的属性,初始化标题栏区域和内容显示区域;

这里比较复杂的就是generateLayout(mDecor)这个函数,我们一起来分析一下吧。

1 //返回用于显示我们设置的页面内容的ViewGroup容器
2 protectedViewGroup generateLayout(DecorView decor) {3    //Apply data from current theme.4    //1、获取窗口的Style属性
5    TypedArray a =getWindowStyle();6
7    if (false) {8        System.out.println("From style:");9        String s = "Attrs:";10        for (int i = 0; i < com.android.internal.R.styleable.Window.length; i++) {11            s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "="
12                    +a.getString(i);13 }14        System.out.println(s);15 }16    //窗口是否是浮动的
17    mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);18    int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)19            & (~getForcedWindowFlags());20    if(mIsFloating) {21 setLayout(WRAP_CONTENT, WRAP_CONTENT);22        setFlags(0, flagsToUpdate);23    } else{24        setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);25 }26    //设置是否不显示title区域
27    if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {28 requestFeature(FEATURE_NO_TITLE);29 }30    //设置全屏的flag
31    if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {32        setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));33 }34
35    if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {36        setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));37 }38
39    WindowManager.LayoutParams params =getAttributes();40    //设置输入法模式
41    if (!hasSoftInputMode()) {42        params.softInputMode =a.getInt(43                com.android.internal.R.styleable.Window_windowSoftInputMode,44                params.softInputMode);45 }46
47    if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled,48 mIsFloating)) {49        /*All dialogs should have the window dimmed*/
50        if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {51            params.flags |=WindowManager.LayoutParams.FLAG_DIM_BEHIND;52 }53        params.dimAmount =a.getFloat(54                android.R.styleable.Window_backgroundDimAmount, 0.5f);55 }56    //窗口动画
57    if (params.windowAnimations == 0) {58        params.windowAnimations =a.getResourceId(59                com.android.internal.R.styleable.Window_windowAnimationStyle, 0);60 }61
62    //The rest are only done if this window is not embedded; otherwise,63    //the values are inherited from our container.
64    if (getContainer() == null) {65        if (mBackgroundDrawable == null) {66            if (mBackgroundResource == 0) {67                mBackgroundResource =a.getResourceId(68                        com.android.internal.R.styleable.Window_windowBackground, 0);69 }70            if (mFrameResource == 0) {71                mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0);72 }73            if (false) {74                System.out.println("Background:"
75                        + Integer.toHexString(mBackgroundResource) + "Frame:"
76                        +Integer.toHexString(mFrameResource));77 }78 }79        mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000);80 }81
82    //Inflate the window decor.83    //2、根据一些属性来选择不同的顶层视图布局,例如设置了FEATURE_NO_TITLE的属性,那么就选择没有Title区域的那么布局;84    //layoutResource布局就是整个Activity的布局,其中含有title区域和content区域,content区域就是用来显示我通过85    //setContentView设置进来的内容区域,也就是我们要显示的视图。
86
87    intlayoutResource;88    int features =getLocalFeatures();89    //System.out.println("Features: 0x" + Integer.toHexString(features));
90    if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {91        if(mIsFloating) {92            layoutResource = com.android.internal.R.layout.dialog_title_icons;93        } else{94            layoutResource = com.android.internal.R.layout.screen_title_icons;95 }96        //System.out.println("Title Icons!");
97    } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {98        //Special case for a window with only a progress bar (and title).99        //XXX Need to have a no-title version of embedded windows.
100        layoutResource = com.android.internal.R.layout.screen_progress;101        //System.out.println("Progress!");
102    } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {103        //Special case for a window with a custom title.104        //If the window is floating, we need a dialog layout
105        if(mIsFloating) {106            layoutResource = com.android.internal.R.layout.dialog_custom_title;107        } else{108            layoutResource = com.android.internal.R.layout.screen_custom_title;109 }110    } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {111        //If no other features and not embedded, only need a title.112        //If the window is floating, we need a dialog layout
113        if(mIsFloating) {114            layoutResource = com.android.internal.R.layout.dialog_title;115        } else{116            layoutResource = com.android.internal.R.layout.screen_title;117 }118        //System.out.println("Title!");
119    } else{120        //Embedded, so no decoration is needed.
121        layoutResource = com.android.internal.R.layout.screen_simple;122        //System.out.println("Simple!");
123 }124
125 mDecor.startChanging();126    //3、加载视图
127    View in = mLayoutInflater.inflate(layoutResource, null);128    //4、将layoutResource的内容添加到mDecor中
129    decor.addView(in, newViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));130    //5、获取到我们的内容显示区域,这是一个ViewGroup类型的,其实是FrameLayout
131    ViewGroup contentParent =(ViewGroup)findViewById(ID_ANDROID_CONTENT);132    if (contentParent == null) {133        throw new RuntimeException("Window couldn't find content container view");134 }135
136    if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {137        ProgressBar progress = getCircularProgressBar(false);138        if (progress != null) {139            progress.setIndeterminate(true);140 }141 }142
143    //6、设置一些背景、title等属性144    //Remaining setup -- of background and title -- that only applies145    //to top-level windows.
146    if (getContainer() == null) {147        Drawable drawable =mBackgroundDrawable;148        if (mBackgroundResource != 0) {149            drawable =getContext().getResources().getDrawable(mBackgroundResource);150 }151 mDecor.setWindowBackground(drawable);152        drawable = null;153        if (mFrameResource != 0) {154            drawable =getContext().getResources().getDrawable(mFrameResource);155 }156 mDecor.setWindowFrame(drawable);157
158        //System.out.println("Text=" + Integer.toHexString(mTextColor) +159        //" Sel=" + Integer.toHexString(mTextSelectedColor) +160        //" Title=" + Integer.toHexString(mTitleColor));
161
162        if (mTitleColor == 0) {163            mTitleColor =mTextColor;164 }165
166        if (mTitle != null) {167 setTitle(mTitle);168 }169 setTitleColor(mTitleColor);170 }171
172 mDecor.finishChanging();173
174    return contentParent;  

其实也就是这么几个步骤:

1、获取用户设置的一些属性与Flag;

2、根据一些属性选择不同的顶层视图布局,例如FEATURE_NO_TITLE则选择没有title的布局文件等;这里我们看一个与图1中符合的顶层布局吧,即layoutResource = c

1 <?xml version="1.0" encoding="utf-8"?>
2
3 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
4     android:orientation="vertical"
5     android:fitsSystemWindows="true">
6     <!-- Popout bar for action modes -->
7     <ViewStub android:id="@+id/action_mode_bar_stub"
8               android:inflatedId="@+id/action_mode_bar"
9               android:layout="@layout/action_mode_bar"
10               android:layout_width="match_parent"
11               android:layout_height="wrap_content" />
12     <!--  title区域-->
13     <FrameLayout14         android:layout_width="match_parent"
15         android:layout_height="?android:attr/windowTitleSize"
16         style="?android:attr/windowTitleBackgroundStyle">
17         <TextView android:id="@android:id/title"
18             style="?android:attr/windowTitleStyle"
19             android:background="@null"
20             android:fadingEdge="horizontal"
21             android:gravity="center_vertical"
22             android:layout_width="match_parent"
23             android:layout_height="match_parent" />
24     </FrameLayout>
25     <!--内容显示区域, 例如main_activity.xml布局就会被放到这个ViewGroup下面 -->
26     <FrameLayout android:id="@android:id/content"
27         android:layout_width="match_parent"
28         android:layout_height="0dip"
29         android:layout_weight="1"
30         android:foregroundGravity="fill_horizontal|top"
31         android:foreground="?android:attr/windowContentOverlay" />
32 </LinearLayout>  

我们可以看到有两个区域,即title区域和content区域,generateLayout函数中的

//5、获取到我们的内容显示区域,这是一个ViewGroup类型的,其实是FrameLayout
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);  

获取的就是xml中id为content的FrameLayout,这个content就是我们的内容显示区域。整个布局对应的效果如下 :

这两个区域就组成了mDecor视图,我们的main_activity.xml就是放在内容视图这个区域的。

3、加载顶层布局文件,转换为View,将其添加到mDecor中;

4、获取内容容器Content Parent,即用于显示我们的内容的区域;

5、设置一些背景图和title等。

在经过这几步,我们就得到了mContentParent,这就是用来装载我们的视图的ViewGroup。再回过头来看setContentView函数:

1 public void setContentView(intlayoutResID) {2     if (mContentParent == null) {3         installDecor();         //1、生成DecorView,并且根据窗口属性加载顶级视图布局、获取mContentParent、设置一些基本属性等
4     } else{5 mContentParent.removeAllViews();6 }7     mLayoutInflater.inflate(layoutResID, mContentParent);//2、将layoutResId加载到mContentParent中,这里的layoutResId就是我们的main_activity.xml
8     final Callback cb =getCallback();9     if (cb != null) {10 cb.onContentChanged();11 }12 }  

我们看看LayoutInflater的inflate函数吧 :

1 /**2 * Inflate a new view hierarchy from the specified xml resource. Throws3 * {@link InflateException} if there is an error.4 *5 * @param resource ID for an XML layout resource to load (e.g.,6 *        <code>R.layout.main_page</code>)7 * @param root Optional view to be the parent of the generated hierarchy.8 * @return The root View of the inflated hierarchy. If root was supplied,9 *         this is the root View; otherwise it is the root of the inflated10 *         XML file.11  */
12 public View inflate(intresource, ViewGroup root) {13     return inflate(resource, root, root != null);14 }15
16 /**17 * Inflate a new view hierarchy from the specified xml resource. Throws18 * {@link InflateException} if there is an error.19 *20 * @param resource ID for an XML layout resource to load (e.g.,21 *        <code>R.layout.main_page</code>)22 * @param root Optional view to be the parent of the generated hierarchy (if23 *        <em>attachToRoot</em> is true), or else simply an object that24 *        provides a set of LayoutParams values for root of the returned25 *        hierarchy (if <em>attachToRoot</em> is false.)26 * @param attachToRoot Whether the inflated hierarchy should be attached to27 *        the root parameter? If false, root is only used to create the28 *        correct subclass of LayoutParams for the root view in the XML.29 * @return The root View of the inflated hierarchy. If root was supplied and30 *         attachToRoot is true, this is root; otherwise it is the root of31 *         the inflated XML file.32  */
33 public View inflate(intresource, ViewGroup root, boolean attachToRoot) {34     if (DEBUG) System.out.println("INFLATING from resource:" +resource);35     XmlResourceParser parser =getContext().getResources().getLayout(resource);36     try{37         returninflate(parser, root, attachToRoot);38     } finally{39 parser.close();40 }41 }  

实际上就是将layoutResId这个布局的视图附加到mContentParent中。

DecorView

移步 : DecorView 。

ViewGroup

ViewGroup从语义上来说就是视图组,它也继承自View类,它其实就是视图的容器。我们看官方的定义 :

* A ViewGroup isa special view that can contain other views* (called children.) The view group is the base class forlayouts and views* containers. This classalso defines the* {@link android.view.ViewGroup.LayoutParams} class which serves as the base
* class for layouts parameters.  

我们通过ViewGroup来组织、管理子视图,例如我们常见的FrameLayout、LinearLayout、RelativeLayout、ListView等都是ViewGroup类型,总之只要能包含其他View或者ViewGroup的都是ViewGroup类型。使用ViewGroup来构建视图树。

View

View就是UI界面上的一个可见的组件,任何在UI上可见的都为View的子类。我们看官方定义 :

TextView、Button、ImageView、FrameLayout、LinearLayout、ListView等都是View的子类。

这样,ViewGroup类型的视图管理嵌套在里面的ViewGroup以及View控件组成了丰富多彩的用户界面。例如我们开篇的Hello World的视图结构是这样的 :

总结

整个窗口由Title区域和Content区域组成,Content区域就是我们要显示内容的区域,在这个区域中mContentParent是根ViewGroup,由mContentParent组织、管理其子视图,从而构建整个视图树。当Activity启动时,就将这些内容就会显示在手机上。

转载于:https://www.cnblogs.com/ganchuanpu/p/8394775.html

Activity的setContentView的流程相关推荐

  1. 深入理解Activity启动流程(三)–Activity启动的详细流程2

    本文原创作者:Cloud Chou. 欢迎转载,请注明出处和本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 深入理解Activity启动流程(一)--A ...

  2. Activity页面的绘制流程

    一.引言 很多朋友都认为Activity的页面绘制是在Activity的onResume方法执行完成就被成功绘制成功了,认为这个时候我们就可以看到我们写的页面了.那真的是这样嘛?其实并不然,Activ ...

  3. activity及其窗口显示流程

    时序图预览 activity及其窗口显示流程图 activity的启动流程可参考:activity启动流程图 关键代码分析 ActivityThread 接收框架 (ActivityTaskManag ...

  4. android setContentView处理流程

    1. Activity在onCreate()方法之前调用attach()方法,在attach方法中会创建Window对象.Window对象创建时并没有创建Decor对象. 2. 用户在Activity ...

  5. 从源码的角度说说Activity的setContentView的原理

    我们在Activity开发的时候天天会用到这个方法,有时候还需要根据需求在setContentView调用的时候做一些动作,因此我们就需要知道它内部是如何工作的,我们来一起看一下: setConten ...

  6. 点击应用图标-应用(Activity)的启动流程

    一 前言 点击应用图标后会去启动应用的LauncherActivity,如果LancerActivity所在的进程没有创建,还会创建新进程,整体的流程就是一个Activity的启动流程.Activit ...

  7. activity idea编写bpmn流程文件

    idea 的bpmn插件支持不好, 1.画流程图,注意排他网关流程的条件, 2.复制一份xml文件出来, 头部替换: <?xml version="1.0" encoding ...

  8. 从源码的角度说说Activity的setContentView的原理(二)

    前文http://blog.csdn.net/sahadev_/article/details/49072045虽然讲解了LayoutInflate的整个过程,但是其中很多地方是不准确不充分的,这一节 ...

  9. activity工作流调用子流程 callActivity

    最近项目中需要用到工作流,其中需要用到工作流中的调用子流程功能,折腾半天完工之后记录一下. 主流程图 子流程图 一个简单的例子说明一下 最关键的是在调用子流程这个模块的properties 中配置要调 ...

最新文章

  1. 使用现场总线更快更远
  2. 2021年度脑机接口重大事件和进展汇总
  3. 协方差、协方差矩阵的解释意义
  4. 2017.3.31 spring mvc教程(六)转发、重定向、ajax请求
  5. [HEOI2013]ALO(待更)
  6. python如何连接sql server数据库_Python连接SQLServer数据库
  7. JAVA从零开始做微信公众号开发(三)[微信公众平台返回码说明]
  8. C语言指针详解(超级详细)
  9. C语言课程设计超级万年历
  10. Java 打印程序设计
  11. tp6常用功能整理(本人刚学习tp6遇到的常见问题)
  12. 计算机视觉实习面试经历
  13. rar文件ubuntu_如何在Ubuntu上提取RAR文件
  14. CF18B/01背包
  15. 读季琦《创始人·手记》
  16. Linux系统配置网络环境的图文教程(完整版)
  17. 如何快速查看电脑的IP和MAC
  18. 分享5个你可能不知道但非常实用的软件
  19. textarea层级问题
  20. 硼碳氮纳米管的制备(碳纳米管包裹磁性金属复合纳米结构/多孔氧化物掺杂的碳纳米管包裹的碳纳米球/碳氮纳米管包裹纳米金属粒子/碳纳米管包裹Ni纳米线复合材料)

热门文章

  1. 一款简单易用的链式droplist
  2. Go 2将添加错误处理和泛型
  3. 管理云栈将会胜出吗?
  4. 【原创】MySQL 实现Oracle或者PostgreSQL的row_number over 这样的排名语法
  5. python操作Mysql基础
  6. 186. [USACO Oct08] 牧场旅行
  7. KVC(forKey,forKeyPath)
  8. 添加非oracle用户到dba, oinstall组
  9. ARM裸机篇---启动代码分析
  10. CentOS6.9编译安装postgresql和php的pdo_pgsql,pgsql扩展