文章目录
-
- 视图层级关系
-
- PhoneWindow的初始化
-
- ActivityThread.performLaunchActivity
- Activity的setContentView
-
- PhoneWindow.setContentView
- PhoneWindow.installDecor
- PhoneWindow.generateDecor
- PhoneWindow.generateLayout
- 总结
视图层级关系
PhoneWindow的初始化
PhoneWindow 伴随着 Activity 的创建而创建, 而 ActivityThread 掌握着 Activity 的创建.
在ActivityThread的performLaunchActivity 方法中,完成了PhoneWindow的初始化和activity的创建,初始化完 Activity 后, 就调用 Activity 的 onCreate 方法了.
ActivityThread.performLaunchActivity
细节如下:
- 在performLaunchActivity中创建了Activity对象以及Context, theme, PackageInfo 等,且初始化了一个Windows
- 之后调用了方法activity.attach实例化了 PhoneWindow
- 调用 Activity 的 onCreate 方法
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
// 创建 Activity的appContext
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
// 创建 Activity
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
...
} catch (Exception e) {
...
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
if (activity != null) {
...
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
// window 创建了
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
appContext.setOuterContext(activity);
// 初始化 Activity 相关的内容, Activity 的attach这个方法中关联了 window
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
...
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
...
}
return activity;
}
Activity的setContentView
在上述执行完成之后,Activity的onCreat()被执行,进而执行Activity的setContentView,其会调用PhoneWindow.setContentView方法
PhoneWindow.setContentView
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//installDecor 这个方法中, 初始化了 DecorView, mContentParent, 初始化了比如标题,icon, logo, 是否全屏等该 window 的一些基础属性
// 初始化 DecorView
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
//如果没有过渡动画, 并且已经创建过 DecorView
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
// 场景转换(过渡动画)
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, getContext());
transitionTo(newScene);
} else {
// 开始填充我们设置的 XML 布局, 容器为 mContentParent
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
阅读上面代码可知, mContentParent 就是装载我们所有内容的根容器(ViewGroup)了. 在这里, 最关键的代码就是 mLayoutInflater.inflate(layoutResID, mContentParent) , 它就是填充我们的布局的代码了.
PhoneWindow.installDecor
- 初始化mContentParent和顶级ViewGroup :mDecorView
private void installDecor() {
...
mForceDecorInstall = false;
if (mDecor == null) {
// generateDecor方法生成了 DecorView
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
// generateLayout方法生成装载我们的布局的容器
mContentParent = generateLayout(mDecor);
...
}
PhoneWindow.generateDecor
- 初始化mDecorView
protected DecorView generateDecor(int featureId) {
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, getContext().getResources());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
// 实例化了一个 DecorView
return new DecorView(context, featureId, this, getAttributes());
}
PhoneWindow.generateLayout
- 初始化mContentParent以及window的title, titleColor,ActionBar等
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
// 获取当前 window 的 主题
TypedArray a = getWindowStyle();
... // 初始化样式, 例如 windowNoTitle, windowActionBar, windowIsTranslucent, windowSoftInputMode 等等
mDecor.startChanging();
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
...
//设置 windowBackground, title, titleColor 等
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
mDecor.finishChanging();
return contentParent;
}
总结
- 在 ActivityThread 的 performLaunchActivity 中, 创建了 PhoneWindow 并调用了 Activity 的 attach 方法
- 在 Activity 的 attach 方法中, 关联了 PhoneWindow
- 在 Activity 的 setContentView 方法中 获取了 PhoneWindow , 并将 layoutResID 传入 PhoneWindow 的 setContentView 中
- 在 PhoneWindow 的 setContentView 中, 初始化了 DecorView,然后初始化mContentParent,把加载出来的这个布局文件对应的View赋值给mDecor
- 在完成上述逻辑后,会回到installDecor中,再调用LayoutInflater的inflate方法解析我们自己的XML布局文件,也就是我们在自己的Activity中onCreate方法中调用setContentView方法中传入的Layout ID,把解析出来的View添加mContentParent中,这样就把我们自己的Layout添加到mDecor中。
- 在onCreate方法中也即Activity生命周期的第一个方法我们通常会调用setContentView(layoutID),这个过程我们在前面已经说过了,紧接着进行生命周期的第二个方法onResume(通过AMS及Handler机制),最终会通过Handler消息分发机制最终调用到ActivityThread中mH中handleMessage()方法调用what=RESUME_ACTIVITY的逻辑判断体内,即调用handleResumeActivity方法。
- 在handleResumeActivity方法中会调用WindowManagerImpl的addView(mDecor,LayoutParam)把前面创建的DecorView(即从系统加载的那个XML布局文件,同样也包含了我们自己的布局文件)。
- 在WindowManagerImpl内部其实是通过WindowManagerGlobal去完成addView的操作的。
- 在WindowManagerGlobal的addView方法中创建了实例对象ViewRootImpl的,调用了其setView方法,在后面就调用到了performTraversals
-
在后面就依次调用了performMeasure,performLayout,performDraw
注:详细看此处
参考1
参考2