View树的创建过程
当AMS通知应用进程来启动一个Activity任务时,最终这个请求会转化为ActivityThread中的一个消息LAUNCH_ACTIVITY,同类型的消息还是RESUME_ACTIVITY,PAUSE_ACTIVITY等。主线程ActivityThread对这个LAUNCH_ACTIVITY消息的处理是整个ViewTree建立的起点。
private class H extends Handler @ActivityThread.java{
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
//获取scheduleLaunchActivity传递的参数。
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
break;
}
}
}
}
重点关注其中的performLaunchActivity,handleResumeActivity两个调用。
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason)
@ActivityThread.java{
//如果正准备GC,就先跳过。
UnscheduleGcIdler();
//在创建Activity之前,初始化。
WindowManagerGlobal.initialize();
//启动、加载Activity。
Activity a = performLaunchActivity(r, customIntent);
//resume这个Activity。
if (a != null) {
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
}else{
//不管什么原因出现的错误,都只能结束Activity的启动,返回给调用者的code是 RESULT_CANCELED。
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
}
}
1)先分析performLaunchActivity。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) @ActivityThread.java{
ActivityInfo aInfo = r.activityInfo;
//如果intent没有明确给出component,将调用 resolveActivity解析出activity component。
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
Activity activity = null;
//取得类加载器,加载这个Activity。
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
//同样借助类加载器,创建Application对象。
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
Context appContext = createBaseContextForActivity(r, activity);
//attach函数的主要任务是生成PhoneWindow对象,也就是Activity中的mWindow,mWindow分Activity是一对一的关系;还有就是给Activity中的一些变量赋值,如main线程等。
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);
//通过Instrumentation工具,间接调用Activity的OnCreate函数。
mInstrumentation.callActivityOnCreate(activity, r.state);
//把ActivityClientRecord添加到一个arraymap中,其中token是IApplicationToken类型的实例。
mActivities.put(r.token, r);
}
前面生成的PhoneWindow对象可以看做界面的框架抽象,还要生成Activity要显示的内容,以及应用程序共同的装饰部分,如title,actionbar等。这个填充的过程是从setContentView调用开始的,这也是每个Activity的onCreate方法中都会调用这个函数的原因。当然也可以不调用,只是内容部分会为null。
//从layout资源,设置Activity的内容。
public void setContentView(@LayoutRes int layoutResID) {
//调用PhoneWindow的 setContentView方法。
getWindow().setContentView(layoutResID);
//创建一个ActionBar。
initWindowDecorActionBar();
}
public void setContentView(int layoutResID)@PhoneWindow.java {
//mContentParent用于容纳contentView,当其为null时,说明是第一次调用 setContentView,所以调用 installDecor创建一个DecorView,否则就清楚已有的view对象, FEATURE_CONTENT_TRANSITIONS这个flag默认没有设置。
if (mContentParent == null) {
installDecor();
}else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
//根据resourceID创建view对象。
mLayoutInflater.inflate(layoutResID, mContentParent);
}
//mContentParent为null,通过installDecor生成Decorview和mContentParent。
private void installDecor()@PhoneWindow.java {
if (mDecor == null) {
// generateDecor只是创建了一个DecorView对象,赋值给了mDecor。
mDecor = generateDecor(-1);
}else{
mDecor.setWindow(this)
}
// mContentParent是通过 generateLayout产生的。
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
}
}
protected ViewGroup generateLayout(DecorView decor) @PhoneWindow.java{
//获取窗口样式。
TypedArray a = getWindowStyle();
mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
//根据窗口样式,请求窗口属性。
if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);
}else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
requestFeature(FEATURE_ACTION_BAR);
}
//根据窗口样式,设置窗口的flags。
if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
}
//窗口是不是透明的。
mIsTranslucent = a.getBoolean(R.styleable.Window_windowIsTranslucent, false);
//得到这个窗口已经实现的feature,前面的requestFeature的结果会保存到mLocalFeatures(getLocalFeatures())中。
int layoutResource;
int features = getLocalFeatures();
//根据前面设置的feature,挑选匹配的资源 layoutResource。
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
}else if ((features & ((1 << FEATURE_LEFT_ICON) |
(1 << FEATURE_RIGHT_ICON))) != 0) {
}else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
layoutResource = R.layout.screen_custom_title;
}
//把 layoutResource资源inflate成view对象,然后把这个view对象addView到mDecor中。
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
//获取主layout:com.android.internal.R.id.content,也是返回值 mContentParent,这个mContentParent的内容实际有setContentView的资源id来填充。
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
return contentParent;
}
到这里就生成了phoneWindow,和decorView,DecorView除了包括窗口的装饰条(title,ActionBar等)外,还包括窗口的内容即mContentParent。
2)接着分析:handleResumeActivity。
performLaunchActivity过程中生成的ViewTree,要添加到WindowManagerGlobal中,进一步注册到windowmanager中。
final void handleResumeActivity(IBinder token,boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) @ActivityThread.java{
//从之前保存的arraymap中获取 ActivityClientRecord。
ActivityClientRecord r = mActivities.get(token);
//这个调用会执行Activity的onResume函数的调用。
r = performResumeActivity(token, clearHide, reason);
final Activity a = r.activity;
if (r.window == null && !a.mFinished && willBeVisible) {
//Activity对应的窗口,最外围的DecorView。
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
//这里的wm实际是WindowManagerImpl对象。
ViewManager wm = a.getWindowManager();
//指定窗口属性是 TYPE_BASE_APPLICATION。
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
}
//把viewtree注册到windowmanager。
if (a.mVisibleFromClient && !a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
}
WindowManagerImpl的addView方法,直接调用WindowManagerGlobal中的方法。
public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) @WindowManagerGlobal.java{
ViewRootImpl root;
View panelParentView = null;
//检查之前是否已经添加过。
int index = findViewLocked(view, false);
//为这个view生成一个 ViewRootImpl对象。
root = new ViewRootImpl(view.getContext(), display);
//添加到本地的全局变量中,即那三个列表, mViews记录DecorView, mRoots记录ViewRootImpl, mParams记录窗口属性。
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
//通过Viewrootimpl的 setView把DecorView记录到ViewRootImpl中的变量mView中,ViewRootImpl后期做事件传递时会把事件传到mView中处理。这样ViewTree就创建完成了,后面接着的是向WMS申请显示窗口(当然这个显示窗口不是phoneWindow),可以认为是一个surface 是一个layer。
root.setView(view, wparams, panelParentView);
}