setContentView()使用如下:
protected void onCreate(Bundle bundle)
{
super.onCreate(bundle);
this.setContentView(R.layout.hwpay_mybill);
}
Activity实现如下:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
getWindow()返回的是Window类型,他的实例是PhoneWindow,所以会调用到PhoneWindow的setContentView()方法,PhoneWindow类的实现如下:
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
如果mContentParent为null,则调用 installDecor()去初始化mContentParent,mContentParent就是Actvity的layout的父容器,他的id就是com.android.internal.R.id.content,是一个FrameLayout。接下来看installDecor()是如何初始化mContentParent的:
private void installDecor() {
if (mDecor == null) {
//初始化mDecor,因为mDecor(FrameLayout子类)是mContentParent的父容器
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
...
...
...
}
}
mContentParent是调用generateLayout(mDecor)去初始化的:
protected ViewGroup generateLayout(DecorView decor) {
TypedArray a = getWindowStyle();
mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
& (~getForcedWindowFlags());
//此处省略200行代码,主要是解析style里面的一些属性,设置窗口风格(Dialog还是Activity),给Window类变量初始化一些值
//关键代码如下:layoutResource是mContentParent的布局id
int layoutResource;
int features = getLocalFeatures();
//通过features加载不同的布局
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;
} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_title_icons;
}
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {
layoutResource = R.layout.screen_progress;
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_custom_title;
}
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
layoutResource = a.getResourceId(
R.styleable.Window_windowActionBarFullscreenDecorLayout,
R.layout.screen_action_bar);
} else {
layoutResource = R.layout.screen_title;
}
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
layoutResource = R.layout.screen_simple;
}
mDecor.startChanging();
//关键代码块
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
// ......此处代码有省略
return contentParent;
}
通过features给mContentParent配不同的布局,features可以通过requestWindowFeature(featureId)去设置,这些布局都有一个共同的特点,那就是都有一个id为content的FrameLayout,然后通过findViewById找到id为content的FrameLayout,至此mContentParent初始化完成。
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
再回到setContentView(),初始化完mContentParent,
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
采用LayoutInfater将Activity的layout膨胀到mContentParent里面,这样setContenView就执行完了。然后通过onContentChanged()
mLayoutInflater.inflate(layoutResID, mContentParent);
回调onContentChanged(),Activity可以重写这个函数做点事情。
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
但是此时只是初始化好了视图,但是并没有显示,正在显示的时候是在ActivityThread中handleResumeActivity方法中执行完Activity的onResume方法之后,调用到activity的makeVisible得以显示。
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
ViewManager的实例其实是一个WindowManager,远程调用WindowManagerService的addView方法,添加视图。
完了,呵呵,稍微了解一下这个过程就OK了。