Activity的setContentView的流程
最简单的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的流程相关推荐
- 深入理解Activity启动流程(三)–Activity启动的详细流程2
本文原创作者:Cloud Chou. 欢迎转载,请注明出处和本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 深入理解Activity启动流程(一)--A ...
- Activity页面的绘制流程
一.引言 很多朋友都认为Activity的页面绘制是在Activity的onResume方法执行完成就被成功绘制成功了,认为这个时候我们就可以看到我们写的页面了.那真的是这样嘛?其实并不然,Activ ...
- activity及其窗口显示流程
时序图预览 activity及其窗口显示流程图 activity的启动流程可参考:activity启动流程图 关键代码分析 ActivityThread 接收框架 (ActivityTaskManag ...
- android setContentView处理流程
1. Activity在onCreate()方法之前调用attach()方法,在attach方法中会创建Window对象.Window对象创建时并没有创建Decor对象. 2. 用户在Activity ...
- 从源码的角度说说Activity的setContentView的原理
我们在Activity开发的时候天天会用到这个方法,有时候还需要根据需求在setContentView调用的时候做一些动作,因此我们就需要知道它内部是如何工作的,我们来一起看一下: setConten ...
- 点击应用图标-应用(Activity)的启动流程
一 前言 点击应用图标后会去启动应用的LauncherActivity,如果LancerActivity所在的进程没有创建,还会创建新进程,整体的流程就是一个Activity的启动流程.Activit ...
- activity idea编写bpmn流程文件
idea 的bpmn插件支持不好, 1.画流程图,注意排他网关流程的条件, 2.复制一份xml文件出来, 头部替换: <?xml version="1.0" encoding ...
- 从源码的角度说说Activity的setContentView的原理(二)
前文http://blog.csdn.net/sahadev_/article/details/49072045虽然讲解了LayoutInflate的整个过程,但是其中很多地方是不准确不充分的,这一节 ...
- activity工作流调用子流程 callActivity
最近项目中需要用到工作流,其中需要用到工作流中的调用子流程功能,折腾半天完工之后记录一下. 主流程图 子流程图 一个简单的例子说明一下 最关键的是在调用子流程这个模块的properties 中配置要调 ...
最新文章
- 使用现场总线更快更远
- 2021年度脑机接口重大事件和进展汇总
- 协方差、协方差矩阵的解释意义
- 2017.3.31 spring mvc教程(六)转发、重定向、ajax请求
- [HEOI2013]ALO(待更)
- python如何连接sql server数据库_Python连接SQLServer数据库
- JAVA从零开始做微信公众号开发(三)[微信公众平台返回码说明]
- C语言指针详解(超级详细)
- C语言课程设计超级万年历
- Java 打印程序设计
- tp6常用功能整理(本人刚学习tp6遇到的常见问题)
- 计算机视觉实习面试经历
- rar文件ubuntu_如何在Ubuntu上提取RAR文件
- CF18B/01背包
- 读季琦《创始人·手记》
- Linux系统配置网络环境的图文教程(完整版)
- 如何快速查看电脑的IP和MAC
- 分享5个你可能不知道但非常实用的软件
- textarea层级问题
- 硼碳氮纳米管的制备(碳纳米管包裹磁性金属复合纳米结构/多孔氧化物掺杂的碳纳米管包裹的碳纳米球/碳氮纳米管包裹纳米金属粒子/碳纳米管包裹Ni纳米线复合材料)
热门文章
- 一款简单易用的链式droplist
- Go 2将添加错误处理和泛型
- 管理云栈将会胜出吗?
- 【原创】MySQL 实现Oracle或者PostgreSQL的row_number over 这样的排名语法
- python操作Mysql基础
- 186. [USACO Oct08] 牧场旅行
- KVC(forKey,forKeyPath)
- 添加非oracle用户到dba, oinstall组
- ARM裸机篇---启动代码分析
- CentOS6.9编译安装postgresql和php的pdo_pgsql,pgsql扩展