Android布局文件的加载过程分析:Activity.setContentView()源码分析
来源:互联网 发布:内网yum服务器 编辑:程序博客网 时间:2024/06/05 10:56
大家都知道在Activity的onCreate()中调用Activity.setContent()方法可以加载布局文件以设置该Activity的显示界面。本文将从setContentView()的源码谈起,分析布局文件加载所涉及到的调用链。本文所用的源码为android-19.
Step 1 、Activity.setContentView(intresId)
public void setContentView(int layoutResID) {getWindow().setContentView(layoutResID);initActionBar();}public Window getWindow() {return mWindow;}该方法调用了该Activity成员的mWindow,mWindow为Window对象。Windown对象是一个抽象类,提供了标准UI的显示策略和行为策略。在SDK中只有PhoneWindow类实现了Window类,而Window中的setContentView()为空函数,所以最后调用的是PhoneWindow对象的方法。
Step 2 、PhoneWindow.setContentView()
@Overridepublic void setContentView(int layoutResID) {if (mContentParent == null) {installDecor();} else {mContentParent.removeAllViews();}// 将布局文件添加到mContentParent中mLayoutInflater.inflate(layoutResID, mContentParent);final Callback cb = getCallback();if (cb != null && !isDestroyed()) {cb.onContentChanged();}}该方法首先根据mContentParent是否为空对mContentParent进行相应的设置。mContentParent为ViewGroup类型,若其已经初始化了,则移除所有的子View,否则调用installDecor()初始化。接着将资源文件转成View树,并添加到mContentParent视图中。
Step 3、 PhoneWindow.installDecor()
这段代码比较长,下面的伪代码只介绍逻辑,读者可自行查看源码。
private void installDecor() {if (mDecor == null) {/*创建一个DecorView对象并设置相应的属性。DecorView是所有View的根View*/mDecor = generateDecor();mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);mDecor.setIsRootNamespace(true);if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);}}if (mContentParent == null) {/*创建mContentParent对象*/mContentParent = generateLayout(mDecor);// Set up decor part of UI to ignore fitsSystemWindows if appropriate.mDecor.makeOptionalFitsSystemWindows();mTitleView = (TextView)findViewById(com.android.internal.R.id.title);if (mTitleView != null) {mTitleView.setLayoutDirection(mDecor.getLayoutDirection());// 根据features值,设置Title的相关属性if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {View titleContainer = findViewById(com.android.internal.R.id.title_container);if (titleContainer != null) {titleContainer.setVisibility(View.GONE);} else {mTitleView.setVisibility(View.GONE);}if (mContentParent instanceof FrameLayout) {((FrameLayout)mContentParent).setForeground(null);}} else {mTitleView.setText(mTitle);}} else {//若没有Title,则设置ActionBar的相关属性,如回调函数、风格属性mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);if (mActionBar != null) {//.......// 推迟调用invalidate,放置onCreateOptionsMenu在 onCreate的时候被调用mDecor.post(new Runnable() {public void run() {// Invalidate if the panel menu hasn't been created before this.PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);if (!isDestroyed() && (st == null || st.menu == null)) {invalidatePanelMenu(FEATURE_ACTION_BAR);}}});}}}}创建mContentParent对象的代码如下:
protected ViewGroup generateLayout(DecorView decor) {// Apply data from current theme.//获取当前Window主题的属性数据,相关字段的文件位置为:sdk\platforms\android-19\data\res\values\attrs.xml//这些属性值可以在AndroidManifest.xml中设置Activityandroid:theme="",也可以在Activity的onCreate中通过//requestWindowFeature()来设置.注意,该方法一定要在setContentView之前被调用TypedArray a = getWindowStyle(); //获取android:theme=""中设置的theme//根据主题属性值来设置PhoneWindow的特征与布局,包括Title、ActionBar、ActionBar的模式、Window的尺寸等属性。//........// Inflate the window decor.// 根据上面设置的Window feature来确定布局文件// Android SDK内置布局文件夹位置为:sdk\platforms\android-19\data\res\layout典型的窗口布局文件有: R.layout.dialog_titile_icons R.layout.screen_title_icons R.layout.screen_progress R.layout.dialog_custom_title R.layout.dialog_title R.layout.screen_title // 最常用的Activity窗口修饰布局文件 R.layout.screen_simple //全屏的Activity窗口布局文件int layoutResource;int features = getLocalFeatures(); //会调用requesetWindowFeature()// ......mDecor.startChanging();// 将布局文件转换成View数,然后添加到DecorView中View in = mLayoutInflater.inflate(layoutResource, null);decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));//取出作为Content的ViewGroup, android:id="@android:id/content",是一个FrameLayoutViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);if (contentParent == null) {throw new RuntimeException("Window couldn't find content container view");}if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {ProgressBar progress = getCircularProgressBar(false);if (progress != null) {progress.setIndeterminate(true);}}// 将顶层Window的背景、标题、Frame等属性设置成以前的if (getContainer() == null) {//......}mDecor.finishChanging();return contentParent;}总结:setContentView将布局文件加载到程序窗口的过程可概况为:
1、创建一个DecorView对象,该对象将作为整个应用窗口的根视图
2、根据android:theme=""或requestWindowFeature的设定值设置窗口的属性,根据这些属性选择加载系统内置的布局文件
3、从加载后的布局文件中取出id为content的FrameLayout来作为Content的Parent
4、将setContentView中传入的布局文件加载到3中取出的FrameLayout中
最后,当AMS(ActivityManagerService)准备resume一个Activity时,会回调该Activity的handleResumeActivity()方法,
该方法会调用Activity的makeVisible方法 ,显示我们刚才创建的mDecor视图族。
//系统resume一个Activity时,调用此方法 final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) { ActivityRecord r = performResumeActivity(token, clearHide); //... if (r.activity.mVisibleFromClient) { r.activity.makeVisible(); } }makeVisible位于ActivityThread类中,代码如下:
void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); // 获取WindowManager对象 wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE); //使其处于显示状况 }
参考文章:http://blog.csdn.net/qinjuning/article/details/7226787
1 0
- Android布局文件的加载过程分析:Activity.setContentView()源码分析
- 源码分析setContentView加载布局文件的过程
- Android布局加载之setContentView源码分析
- Activity中布局资源layoutResId在setContentView加载过程分析
- Activity的setContentView源码分析
- Activity加载view6.0源码分析---setContentView
- 源码分析 setContentView() 布局加载机制
- Activity.setContentView()源码分析
- android源码分析——由SetContentView串起来的布局加载机制
- Activity 从加载布局文件到显示的过程分析
- 从setContentView分析Android加载布局的流程
- android中布局和View创建的源码分析---setContentView
- Activity的setContentView()方法源码分析
- android视图学习---Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- 从setContentView方法分析Android加载布局流程
- 从setContentView方法分析Android加载布局流程
- 从setContentView方法分析Android加载布局流程
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Yii 国际化的实现
- C#中遍历当前所有进程时存在的陷阱
- 使用sqoop将MySQL数据库中的数据导入Hbase
- web爬虫
- Android Apk自动更新service(直接拿来用)
- Android布局文件的加载过程分析:Activity.setContentView()源码分析
- ubuntu12.04+hadoop2.3.0+eclipse+IHPI安装配置
- leetcode Reverse Words in a String
- 【大家说英语】LIFE World News-20140604&20140605
- 重新播放视频!!
- 约瑟夫问题--循环链表实现
- 人才留得住是因为本身就留得住;留不住的,你永远留不住!
- linux shell彩色输出
- java中Array的常用方法整理