Android中的Window和Windowmanager
什么是window
直接引用作者的原话了,window表示一个窗口的概念,具体实现是phonewindow,通过windowmanager来管理,windowmanager又和windowmanagerservice进行通信,其过程是一个ipc的过程。
Android中的所有视图都是通过window来呈现,无论是activity,dialog,toast都是附加在window上的。
所以,window实际是view的直接管理者。
window与windowmanager
window是通过windowmanager来访问和管理的,比如,我们要在window上添加一个button,具体的步骤就是,新建一个button,设置其属性,然后通过windowmanager.layoutparams来新建其在window上的布局属性。
可以在布局属性中设置一些flag来达到特殊效果,比如,无法获取焦点,不能被点击,在锁屏时显示在窗口上等等。
window也是分层级的,分为三级,分别对应的级别为,1-99,1000-1999,2000-2999,对应于windowmanager.layoutparams的type参数,层级越大的就会显示在上面。
windowmanager常用的有三个方法,添加,更新,移除view
window的内部机制
window的添加过程
首先,通过调用windowmanager来进行第一步,但是windowmanager只是一个接口,具体的操作委派给了windowmanagerimp,windowmanagerimp再调用了windowmanagerglobal来处理
在windowmanagerglobal的addview方法中,主要做了三块内容
1.检查参数的合法性,如果是子window还会进行一些布局参数的调整
2.创建viewrootimp,并将要添加的view添加到列表中去
3.通过viewrootimp来更新界面,完成window的添加,添加的入口函数是scheduleTraversals(),内部调用了一个windowsession对象的addtodisplay方法,这个对象其实是一个binder类型,所以其实质是一次ipc过程
4.在addtodisplay内部,使用了windowmanagerservice来实现window的添加,接下来,就把添加任务交给了windowmanagerservice处理
window的删除过程
- 也是通过windowmanagerimp然后通过windowmanagerglobal来实现的
2.在windowmanagerglobal的removeview方法中,首先差找到要删除view的索引,然后调用removeviewlocked方法来删除
3.在removeview方法中,首先回收输入法,然后调用viewrootimp的die方法来发送一个消息,并把要移除的view加入mDyingViews数组中
4.在die方法中,如果是同步模式,会立即调用dodie方法,否则只会发送一个emptymessage给viewrootimp去调用dodie方法
5.在dodie方法中,调用了dispatchedfromwindow方法来实现真正的移除view,该方法主要做几件事,垃圾回收,通过session的remove方法进行ipc,从而调用windowmanagerservice的removewindow方法,调用view的dispatchdetachedfromwindow方法,通过该方法调用view的一些周期回调,从而进行一些回收资源的收尾工作
6.调用windowmanagerglobal的doremoveview方法刷新数据,将当前window所关联的mroots,mparams,mdyingviews三类对象从中移除
window的更新过程
1.使用windowmanagerglobal的updateviewlayout方法,更新替换要更新的view的layoutparams,通过移除就的,添加新的来实现,然后再替换viewrootimp的layoutparams,通过viewrootimp的setlayoutparams方法来实现,viewrootimp会重新布局,测量,绘制要更新的view,并通过session发起ipc来让windowmanagerservice进行relayoutwindow更新window.
window的创建过程
通过上面,可以知道,view是android中视图的呈现方式,依赖于window,下面就三个主要的视图的创建方式进行总结
Activity的window创建过程
1.由于activity的创建过程十分复杂,我们直接看ActivityThread中的performLaunchActivity方法,首先,使用类加载器获取activity的实例对象,然后创建相关的上下文变量,再用activity的attach方法将这些上下文变量与activity关联起来
2.在attach方法中,会使用policymanager来创建window实例,然后为其设置回调接口,这样当事件发生时就可以回调这些activity方法了
3.在setContentView这个常用函数中,其实是把工作交给了window去处理,而window的实现就是phoneWindow
4.phoneWindow中,具体做了以下几步
4.1 检查是否有decorview,没有就创建
4.2 把view添加到decorview的mcontentparent中,使用了layoutinflater
4.3 回掉activity的oncontentviewchanged方法通知activity视图改变
5 最后,在onresume中调用makevisible方法,将DecorView加入了window之中,用了addview,然后将其显示出来
Dialog的Window创建过程
1.创建window,使用policymanager,与上面的过程相同
2.初始化decorview,并添加视图,也与上面内容相似
3.将decorview添加到window中,也与activity的对应过程相同
4.关闭时从window移除decorview
Toast的Window创建过程
从toast的show方法开始
1.通过调用notificationmanagerservice的enqeueToast方法,传入包名,回掉实例,持续时间
2.enqeueToast中,把请求封装为record对象,然后加入一个数组中,然后nms通过showNextToastLocked方法来显示当前toast
3.显示是通过回调record对象的tn来实现的,这是一个ipc的过程,使用的是binder
4.nms通过调用scheduleTimeoutLocked发送延时消息,来隐藏现在的toast并将其从队列中移除,显示下一个toast