Android GUI系统-ViewTree的创建(二)

来源:互联网 发布:地面站软件下载 编辑:程序博客网 时间:2024/05/19 16:06

View树的创建过程

AMS通知应用进程来启动一个Activity任务时,最终这个请求会转化为ActivityThread中的一个消息LAUNCH_ACTIVITY,同类型的消息还是RESUME_ACTIVITYPAUSE_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;}}}}

重点关注其中的performLaunchActivityhandleResumeActivity两个调用。

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中的一些变量赋值,如UI线程,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要显示的内容,以及应用程序共同的装饰部分,如titleactionbar等。这个填充的过程是从setContentView调用开始的,这也是每个ActivityonCreate方法中都会重写这个函数的原因。


//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,和decorViewDecorView除了包括窗口的装饰条(titleActionBar等)外,还包括窗口的内容即mContentParent


2)接着分析:handleResumeActivity

performLaunchActivity过程中生成的ViewTree,要添加到WindowManagerGlobal中,进一步注册到WMS中。

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注册到WMS。if (a.mVisibleFromClient && !a.mWindowAdded) {a.mWindowAdded = true;wm.addView(decor, l);}}


WindowManagerImpladdView方法,直接调用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);}


原创粉丝点击