博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Activity.setContentView()源码分析
阅读量:3594 次
发布时间:2019-05-20

本文共 5361 字,大约阅读时间需要 17 分钟。

大家都知道在Activity的onCreate()中调用Activity.setContent()方法可以加载布局文件以设置该Activity的显示界面。本文将从setContentView()的源码谈起,分析布局文件加载所涉及到的调用链。本文所用的源码为android-19.

Step 1  、Activity.setContentView(intresId)

[java] 
  1. public void setContentView(int layoutResID) {  
  2.     getWindow().setContentView(layoutResID);  
  3.     initActionBar();  
  4. }  
  5.   
  6. public Window getWindow() {  
  7.     return mWindow;  
  8. }  
该方法调用了该Activity成员的mWindow,mWindow为Window对象。Windown对象是一个抽象类,提供了标准UI的显示策略和行为策略。在SDK中只有PhoneWindow类实现了Window类,而Window中的setContentView()为空函数,所以最后调用的是PhoneWindow对象的方法。

Step 2  、PhoneWindow.setContentView()

[java] 
  1. @Override  
  2. public void setContentView(int layoutResID) {  
  3.     if (mContentParent == null) {  
  4.         installDecor();  
  5.     } else {  
  6.         mContentParent.removeAllViews();  
  7.     }  
  8.     // 将布局文件添加到mContentParent中  
  9.     mLayoutInflater.inflate(layoutResID, mContentParent);  
  10.     final Callback cb = getCallback();  
  11.     if (cb != null && !isDestroyed()) {  
  12.         cb.onContentChanged();  
  13.     }  
  14. }  
该方法首先根据mContentParent是否为空对mContentParent进行相应的设置。mContentParent为ViewGroup类型,若其已经初始化了,则移除所有的子View,否则调用installDecor()初始化。接着将资源文件转成View树,并添加到mContentParent视图中。

Step 3、 PhoneWindow.installDecor() 

这段代码比较长,下面的伪代码只介绍逻辑,读者可自行查看源码。

[java] 
  1. private void installDecor() {  
  2.     if (mDecor == null) {  
  3.         /*创建一个DecorView对象并设置相应的属性。DecorView是所有View的根View*/  
  4.         mDecor = generateDecor();  
  5.         mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);  
  6.         mDecor.setIsRootNamespace(true);  
  7.         if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {  
  8.             mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);  
  9.         }  
  10.     }  
  11.     if (mContentParent == null) {  
  12.         /*创建mContentParent对象*/  
  13.         mContentParent = generateLayout(mDecor);  
  14.   
  15.         // Set up decor part of UI to ignore fitsSystemWindows if appropriate.  
  16.         mDecor.makeOptionalFitsSystemWindows();  
  17.           
  18.         mTitleView = (TextView)findViewById(com.android.internal.R.id.title);  
  19.         if (mTitleView != null) {  
  20.       
  21.             mTitleView.setLayoutDirection(mDecor.getLayoutDirection());  
  22.             // 根据features值,设置Title的相关属性  
  23.             if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {  
  24.                 View titleContainer = findViewById(com.android.internal.R.id.title_container);  
  25.                 if (titleContainer != null) {  
  26.                     titleContainer.setVisibility(View.GONE);  
  27.                 } else {  
  28.                     mTitleView.setVisibility(View.GONE);  
  29.                 }  
  30.                 if (mContentParent instanceof FrameLayout) {  
  31.                     ((FrameLayout)mContentParent).setForeground(null);  
  32.                 }  
  33.             } else {  
  34.                 mTitleView.setText(mTitle);  
  35.             }  
  36.         } else {  
  37.             //若没有Title,则设置ActionBar的相关属性,如回调函数、风格属性  
  38.             mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);  
  39.             if (mActionBar != null) {  
  40.                 //.......  
  41.                   
  42.                 // 推迟调用invalidate,放置onCreateOptionsMenu在 onCreate的时候被调用  
  43.                 mDecor.post(new Runnable() {  
  44.                     public void run() {  
  45.                         // Invalidate if the panel menu hasn't been created before this.  
  46.                         PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);  
  47.                         if (!isDestroyed() && (st == null || st.menu == null)) {  
  48.                             invalidatePanelMenu(FEATURE_ACTION_BAR);  
  49.                         }  
  50.                     }  
  51.                 });  
  52.             }  
  53.         }  
  54.     }  
  55. }  
创建mContentParent对象的代码如下:

[java] 
  1. protected ViewGroup generateLayout(DecorView decor) {  
  2.     // Apply data from current theme.  
  3.     //获取当前Window主题的属性数据,相关字段的文件位置为:sdk\platforms\android-19\data\res\values\attrs.xml  
  4.     //这些属性值可以在AndroidManifest.xml中设置Activityandroid:theme="",也可以在Activity的onCreate中通过  
  5.     //requestWindowFeature()来设置.注意,该方法一定要在setContentView之前被调用  
  6.     TypedArray a = getWindowStyle();   
  7.     //获取android:theme=""中设置的theme  
  8.     //根据主题属性值来设置PhoneWindow的特征与布局,包括Title、ActionBar、ActionBar的模式、Window的尺寸等属性。  
  9.     //........  
  10.       
  11.   
  12.     // Inflate the window decor.  
  13.     // 根据上面设置的Window feature来确定布局文件  
  14.     // Android SDK内置布局文件夹位置为:sdk\platforms\android-19\data\res\layout  
  15.     典型的窗口布局文件有:  
  16.           R.layout.dialog_titile_icons                          R.layout.screen_title_icons  
  17.           R.layout.screen_progress                             R.layout.dialog_custom_title  
  18.           R.layout.dialog_title     
  19.           R.layout.screen_title         // 最常用的Activity窗口修饰布局文件  
  20.           R.layout.screen_simple    //全屏的Activity窗口布局文件  
  21.       
  22.     int layoutResource;  
  23.     int features = getLocalFeatures(); //会调用requesetWindowFeature()  
  24.     // ......  
  25.     mDecor.startChanging();  
  26.     // 将布局文件转换成View数,然后添加到DecorView中  
  27.     View in = mLayoutInflater.inflate(layoutResource, null);  
  28.     decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));  
  29.     //取出作为Content的ViewGroup, android:id="@android:id/content",是一个FrameLayout  
  30.     ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);  
  31.     if (contentParent == null) {  
  32.         throw new RuntimeException("Window couldn't find content container view");  
  33.     }  
  34.   
  35.     if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {  
  36.         ProgressBar progress = getCircularProgressBar(false);  
  37.         if (progress != null) {  
  38.             progress.setIndeterminate(true);  
  39.         }  
  40.     }  
  41.   
  42.     // 将顶层Window的背景、标题、Frame等属性设置成以前的  
  43.     if (getContainer() == null) {  
  44.         //......  
  45.     }  
  46.   
  47.     mDecor.finishChanging();  
  48.   
  49.     return contentParent;  
  50. }  
总结: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视图族。

[java] 
  1. //系统resume一个Activity时,调用此方法    
  2. final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {    
  3.     ActivityRecord r = performResumeActivity(token, clearHide);    
  4.     //...    
  5.      if (r.activity.mVisibleFromClient) {    
  6.          r.activity.makeVisible();    
  7.      }    
  8. }   
makeVisible位于ActivityThread类中,代码如下:

[java] 
  1. void makeVisible() {    
  2.     if (!mWindowAdded) {    
  3.         ViewManager wm = getWindowManager();   // 获取WindowManager对象    
  4.         wm.addView(mDecor, getWindow().getAttributes());    
  5.         mWindowAdded = true;    
  6.     }    
  7.     mDecor.setVisibility(View.VISIBLE); //使其处于显示状况    
  8. }    

参考文章:

转载地址:http://rggwn.baihongyu.com/

你可能感兴趣的文章
LinkedHashSet的使用
查看>>
JS 整数与罗马数字相互转换(1~3999)
查看>>
React native 内使用div等html标签的注意事项
查看>>
react native复制项目或新建项目运行时报错
查看>>
react native跨界面传输数据实例(已完成)
查看>>
html文件显示数据库数据的过程指引
查看>>
isMounted(...)is deprecated in plain JavaScript React classes解决方法
查看>>
react native更改程序名
查看>>
React native 隐藏导航的顶部标题栏
查看>>
TabNavigator简单属性(慢慢更新)
查看>>
react native多种导航混合使用
查看>>
Eclipse知识点精粹
查看>>
Android Studio 连接 Genymotion
查看>>
Android Studio的配置
查看>>
Android Studio知识点精华(精粹版)
查看>>
Android Studio设置字体大小
查看>>
Eclipse的常用快捷键
查看>>
精简分析BF算法与KMP算法
查看>>
typedef struct和struct区别
查看>>
C语言自主设计迷宫类游戏实例
查看>>