Activity的view添加到window

在“Activity中view的加载”文章中可知,当用户在Activity中提供的view添加到DecorView后,view的加载就完成,再经过绘制就能显示出来了。那么DecorView又是如何添加到窗口中的或者说Activity关联的view又是如何被添加到窗口中的?

Activitythread的scheduleLaunchActivity方法负责启动Activity,经过Handerl处理执行到handleLaunchActivity

Activity a = performLaunchActivity(r, customIntent);
handleResumeActivity(r.token, false, r.isForward,!r.activity.mFinished && !r.startsNotResumed);

performLaunchActivity会创建待启动Activity类的一个实例,并调用其attach方法进行初始化,然后调用Activity的onCreate,onStart方法,在onCreate中会调用用户实现的setContentView,在setContentView中会创建Activity关联的DecorView。handleResumeActivity会调用onResume方法,让Activity处于可见状态并把其关联的DecorView添加到WindowManager中。attach方法做了很多工作,重点是创建了关联的window对象即PhoneWindow对象,获得关联的WindowManager对象,主要代码:

mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindowManager = mWindow.getWindowManager();

makeNewWindow的过程创建了PhoneWindow对象,setCallback把Activity对象传递到关联的Window对象中便于窗口的状态发生改变时能够通知Activity,getWindowManager得到WindowManager对象。继续看如何添加view的

if (r.window == null && !a.mFinished && willBeVisible) {
	r.window = r.activity.getWindow();
	View decor = r.window.getDecorView();
	decor.setVisibility(View.INVISIBLE);
	ViewManager wm = a.getWindowManager();
	WindowManager.LayoutParams l = r.window.getAttributes();
	a.mDecor = decor;
	l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
	l.softInputMode |= forwardBit;
	if (a.mVisibleFromClient) {
		a.mWindowAdded = true;
		wm.addView(decor, l);
	}

首先获得关联的window对象和根view并把view的属性设为不可见,因为此时还没有加入到窗口中,所以设为不可见。获得关联的WindowManager对象,获得窗口的属性并设窗口类型为“应用程序窗口”,最后调用WindowManager的addView方法把Activity的view添加到窗口中,并置标志位mWindowAdded为true,表示view添加成功。有的文章中提到在Activity的makeVisible中添加view,这个不是完全正确

void makeVisible() {
	if (!mWindowAdded) {
		ViewManager wm = getWindowManager();
		wm.addView(mDecor, getWindow().getAttributes());
		mWindowAdded = true;
	}
	mDecor.setVisibility(View.VISIBLE);
}

mWindowAdded已经为true了,所以不会在执行添加动作,makeVisible的重要工作让decorview可见。读到此处可知,先是让Activity可见,然后view才能可见。再看WindowManager的addView的具体实现,WindowManager的实现为WindowManagerImpl,添加、删除、更新窗口都是在这个类中进行的,这个类的实际的操作还是由WindowManagerGlobal进行,相关代码:

root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
root.setView(view, wparams, panelParentView);

创建view关联的ViewRootImpl对象并初始化,设置view的布局属性,把view添加到mViews列表中保存起来,ViewRootImpl对象添加到mRoots列表中,布局参数存储到mParams列表中,再把view传递到ViewRootImpl的setView中,看setView做了什么

mAttachInfo.mRootView = view;
mAdded = true;
requestLayout();

把view放在AttachInfo对象中保存起来,AttachInfo是View的内部类,其作用是保存即将被添加到窗口中的view的信息的。mAdded表示添加成功的标志,requestLayout方法很重要,会刷新view树,对view进行测量、布局、绘制,经过这个步骤后,用户提供的视图显示出来。

res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mInputChannel);

addToDisplay的实现在Session中,这里是一个binder通信过程,Session的addToDisplay会传递到WindowManagerService的addWindow,添加窗口真实在这里发生的。从WindowManagerGlobal到WindowManagerService这几个过程可以看到,添加view变成了添加窗口,view都被保存在列表中,在创建每一个ViewRootImpl对象时都会创建对应的window对象

mWindow = new W(this);

最终在WindowManagerService的addWindow中完成窗口的添加

win = new WindowState(this, session, client, token,attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
mWindowMap.put(client.asBinder(), win);

用传递过来的窗口对象client作为参数创建了一个WindowState对象,然后把该对象作为值,把传递过来的窗口IBinder句柄作为键,作为一个键值对放在HashMap中保存起来,等下次使用的时候就可以从HashMap中根据窗口IBinder句柄取出对应的窗口对象。从这里可以看出,添加窗口的过程实际上变成了添加WindowState,WindowState实际上就表示一个窗口,这个窗口代表了被添加的窗口,也就是说,添加view最后变成添加窗口。window只是一个抽象的概念,其存在形式为view,添加view变成了添加窗口。窗口添加好后,相关事件就可以通过窗口传递给viewRootIml,再由viewRootIml传递给view。比如窗口焦点事件,如果焦点发生了变化,事件就会通过WindowState回调给上面参数client,client就是IWindow对象,IWindow对象传递给viewRootIml,viewRootIml又会传递给view。

本文的标题是“Activity的view添加到window中”,可以理解为添加Activity关联的窗口到窗口管理器中。在这个过程中会把decorview显示出来并把用户提供的视图绘制出来。

回答艺术开发探索的问题,一个应用有多少个window?

一个窗口对应一个view,一个view对应一个viewRootImpl,每个Activity启动的时候会关联一个窗口,那么每个Activity都会对应一个窗口,如果有N个Activity就会有N个窗口,但是窗口并不都是同时存在的,只有当Activity处于活动或者可见状态时窗口才会存在。一个窗口对应一个view,这里的view不是开发者写的textview或者button,而是根decorview。除了Activity,还有各种dialog,toast,弹出式菜单等,这些UI都会有对应的窗口,只要能想到和用户交互的地方都会存在窗口的概念。所以一个应用包含多个窗口,具体数目看这个应用有多少个Activity、dialog、toast等,而且这些视图必须处于活动或可见状态。

备注:可以验证这个说法,写一个小Demo,然后在创建WindowState和Decorview地方加上打印,每次启动Activity会不会打印到。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值