android view加载过程,Android布局文件的加载过程分析:Activity.setContentView()源码分析...

大家都知道在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();

}

// 将布局文件添加到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",是一个FrameLayout

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);

}

}

// 将顶层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

原文:http://blog.csdn.net/bigconvience/article/details/28626631

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值