本文共 5361 字,大约阅读时间需要 17 分钟。
大家都知道在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()
- @Override
- public void setContentView(int layoutResID) {
- if (mContentParent == null) {
- installDecor();
- } else {
- mContentParent.removeAllViews();
- }
-
- 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) {
-
- mDecor = generateDecor();
- mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
- mDecor.setIsRootNamespace(true);
- if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
- mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
- }
- }
- if (mContentParent == null) {
-
- mContentParent = generateLayout(mDecor);
-
-
- mDecor.makeOptionalFitsSystemWindows();
-
- mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
- if (mTitleView != null) {
-
- mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
-
- 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 {
-
- mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
- if (mActionBar != null) {
-
-
-
- mDecor.post(new Runnable() {
- public void run() {
-
- PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
- if (!isDestroyed() && (st == null || st.menu == null)) {
- invalidatePanelMenu(FEATURE_ACTION_BAR);
- }
- }
- });
- }
- }
- }
- }
创建mContentParent对象的代码如下:
- protected ViewGroup generateLayout(DecorView decor) {
-
-
-
-
- TypedArray a = getWindowStyle();
-
-
-
-
-
-
-
-
- 典型的窗口布局文件有:
- 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
- R.layout.screen_simple
-
- int layoutResource;
- int features = getLocalFeatures();
-
- mDecor.startChanging();
-
- View in = mLayoutInflater.inflate(layoutResource, null);
- decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-
- ViewGroup 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);
- }
- }
-
-
- 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视图族。
-
- 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();
- wm.addView(mDecor, getWindow().getAttributes());
- mWindowAdded = true;
- }
- mDecor.setVisibility(View.VISIBLE);
- }
参考文章: 转载地址:http://rggwn.baihongyu.com/