lin20080410的专栏

从站在巨人的肩上,向成为巨人迈进... 互相学习!

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

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中的一些变量赋值,如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方法中都会调用这个函数的原因。当然也可以不调用,只是内容部分会为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,和decorViewDecorView除了包括窗口的装饰条(titleActionBar等)外,还包括窗口的内容即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);
	}
}


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);
}


阅读更多
版权声明:笔记记录,互相学习,不足之处,欢迎指正! https://blog.csdn.net/lin20044140410/article/details/78868550
想对作者说点什么? 我来说一句

viewTree

u011052996 u011052996

2015-03-20 14:11:26

阅读数:304

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭