1.activity的window创建
activity的window创建过程跟activity的启动过程息息相关,activity启动过程中最终会由ActivityThread中的performLaunchActivity()方法来完成整个启动,在该方法内部会通过类加载器加载创建activity的实例对象,并且通过attach方法为activity关联运行过程中所依赖的一些列上下文环境。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
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);
return activity;
}
在activity的attach方法中系统会创建activity所属的window对象,并为其设置回调接口,如下
//6.0以上源码
mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
//5.0源码
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
可以看到不同版本的SDK源码在window创建这里是有点不一样,5.0以下的代码通PolicyManager.makeNewWindow方法来创建window对象,PolicyManager是一个策略类,它的真正实现是Policy类,该类中的makeNewWindow方法实现如下:
public Window makeNewWindow(Context context){
return new PhoneWindow(context);
}
从5.0版本源码可以看出最终也是new了一个PhoneWindow对象,而6.0的源码直接mWindow = new PhoneWindow(this, window);,其实两者本质是一样的,。到这里,window已经创建完了,下面分析activity的视图是如何显示在window上的。而 Activity 的视图是由 setContentView 提供,所以从 setContentView 入手,它的源码如下:
public void setContentView(int layoutResID){
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
从该方法可以看出,activity将具体的实现交给了window处理,而window的实现类是phonewindow,因此看phonewindow中的setContentView方法即可;
public void setContentView(View view, ViewGroup.LayoutParams params) {
// 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.
//1.如果没有DecorView 就创建它
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
view.setLayoutParams(params);
final Scene newScene = new Scene(mContentParent, view);
transitionTo(newScene);
} else {
//将2.view添加到DecorView的mContentParent
//6.0的写法
mContentParent.addView(view, params);
//5.0的写法:
//mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
该方法有下面几个步骤:
1.如果没有DecorView 就创建它
DecorView 是activity中的顶级view,它的创建过程由installDecor方法来完成,该方法内部会通过generateDecor方法来直接创建DecorView ,这个时候DecorView 还是一个空白的FrameLayout, 接着,为了初始化DecorView 的结构,在installDecor方法内部还会调用generateLayout方法来加载具体的布局文件到DecorView 。