Window Tree
Window Tree
WMS责任主要是负责收集各个窗口的数据,比如透明度,层级值,位置参数,大小等,然后将窗口的这些参数都传给Surface层去渲染;
WMS通过创建一个类似树形结构,来管理所有的窗口,下图为Window Tree简单介绍
![](https://img.haomeiwen.com/i1713897/8160ff48094259aa.jpg)
Window Tree如何建立
AMS和WMS关系极其密切,基本上每一种数据结构都与之有所对应,不同点在与AMS关心的最小粒度是Activity,而WMS关心的最小粒度是窗口;所以AppWindowToken包含AppWindowToken的构建时机和顺序都是根据AMS决定的,而AppWindowToken以下的部分就是完全由WMS来控制.
虽然AppWindowToken创建时机和顺序都是AMS决定的;但是每个AppWindowToken对应着一个Activity,了解它是很有必要的,所以整个WMS数的构建从AppWindowToken开始说起[WindowToken暂时不分析]:
AppWindowToken创建时机
从startActivity()到Activity.onCreate()方法,大致我分了三步[Android系统是非常繁琐,整个过程所要做的事情非常之多]
- 启动一个Activity的时候,会首先查看对应的进程是否启动,没启动就先启动对应的进程
- 然后创建Activity对应的AppWindowToken,同时添加进WMS树中
- 最后是大家熟悉的Activity的onCreate等;
注意这个时候Activity对应的窗口[WindowState]并没有添加进来即AppWindowToken并没有对应的child;
WindowState创建时机
接着上一个流程来说,在Activity的onCreate时候Activity已经创建好了对应的View树[更准确的说是setContentView],View数的树顶是一个DecorView,此时DecorView处于游离状态,对于开发者来说,我们如果想要添加一个窗口需要做些什么呢,没错就是通过WindowManager.addView(decorView, lp); Android系统同样也是这样操作,时机就是回调Activity.onResume之前.
所以创建WindowState的源头是WindowManager.addView(decorView, lp)方法,而真正创建WindowState的是在WMS.addWindow方法
WMS.addWindow方法大概做了3件事
- 找到属于该窗口的屏幕[DisplayContent]
- 找到属于该窗口的AppWindowToken
- 创建WindowState并且存入AppWindowToken中即添加到WMS树中
这里其实是有两种情况: 1. 如果WindowState是Dialog或者Activity等应用窗口则根据WindowState的mBaseLayer从小到大的顺序添加到AppWindowToken中,如果是PopupWindow等子窗口,则不会添加到AppWindowToken,而是根据WindowState的mSubLayer从小到大的顺序添加进WindowState中,因为此处是Activity的窗口所以直接是添加到AppWindowToken中
至此Window Tree分支创建过程大致分析完毕,开发者可通过调用一个有一个接口来丰富Window Tree.
强烈建议自已分析一下WindowManager.addView(decorView, lp)这个方法,这个过程包含了很多必要的知识点比如View Tree的测量布局绘制,View树对外的代理官ViewRootImpl的创建,为什么PopupWindow的context不能使用Application而是要使用Activity的等等等;
Window层级处理
Android窗口类型
窗口类型分为三种
应用窗口: 如Activity, Dialog
子窗口: PopupWindow
系统窗口: 系统弹窗等
WindowState属性 mBaseLayer ; mSubLayer ; mLayer
每个WindowState都有三个属性 mBaseLayer ; mSubLayer ; mLayer;
mBaseLayer,mSubLayer都是由WindowManager.LayoutParam中的type决定,系统窗口和应用窗口的mSubLayer=0,type决定mBaseLayer;子窗口的mBaseLayer值对应着父窗口的mBaseLayer,而type决定着mSubLayer;
mLayer是通过整合所有窗口计算出来的,详见下面窗口的层级处理;
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
// The multiplier here is to reserve space for multiple
mBaseLayer = mPolicy.getWindowLayerLw(parentWindow) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; // 应用窗口之间和系统窗口之间都是预留了很大的空间的,目的在于后续层级处理的时候预留插入的位置
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
mIsChildWindow = true;
parentWindow.addChild(this, sWindowSubLayerComparator);
} else {
mBaseLayer = mPolicy.getWindowLayerLw(this) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = 0;
mIsChildWindow = false;
显然系统窗口的mBaseLayer是大于应用窗口;对于子窗口来说它是依附与父窗口的,可以在父窗口的下面也可以在父窗口的上层,这取决于mSubLayer的正负值
Android 8.0 层级处理
因为Window Tree已经有顺序了,所以只需要按照顺序遍历所有WindowState,然后根据mBaseLayer进行累加并赋值给mLayer
遍历的源头来自WindowLayersController.assignWindowLayers; 累加规则在WindowLayersController.mAssignWindowLayersConsumer;
WindowLayersController.assignWindowLayers 部分代码
displayContent.forAllWindows(mAssignWindowLayersConsumer, false /* traverseTopToBottom */); //开始遍历
adjustSpecialWindows(); //调整特殊层级位置
WindowLayersController.mAssignWindowLayersConsumer 部分代码
int oldLayer = w.mLayer;
if (w.mBaseLayer == mCurBaseLayer) {
mCurLayer += WINDOW_LAYER_MULTIPLIER; // WINDOW_LAYER_MULTIPLIER
} else {
mCurBaseLayer = mCurLayer = w.mBaseLayer;
}
assignAnimLayer(w, mCurLayer);
collectSpecialWindows(w) 收集一些特殊的窗口,然后调整层级位置
有些窗口比较特殊,它的层级需要根据其他窗口而定,比如输入法窗口,它是必须高于应用窗口的, 所以在adjustSpecialWindows中会调整输入法窗口的mLayer值,这也是为什么每个层级之间都需要预留位置;
最终WMS还是会遍历整个Window Tree,将每个WindowState对应的层级数据交付给与之对应的WindowSurfaceController中,由WindowSurfaceController再交给Surface层
WMS是以树的形式管理WindowState[Window Tree],而Surface层没有树结构,只是通过WindowState的mLayer来确定Surface的位置
Android 9.0 层级处理
Android 9.0 有一个比较大的变动在于将窗口动画移动到Surface层处理,避免卡顿;有兴趣可以看看Here
所以Android9.0 中已经没有WindowLayersController.java了;取而代之的是有层级概念的SurfaceControl[即Surface Tree结构如图],这样surface层就可以通过按照顺序遍历这颗树即可获取到Surface位置
单从层级的角度来看,这种结构方便动态更改:如果需要调整某个层级,就比较简单不需要提前预留位置,直接可以通过设置assignRelativeLayer,添加一个新的分支,同时还可以在这个新分支做更多的处理
![](https://img.haomeiwen.com/i1713897/ee2f48c5cb6a4457.jpg)
本文只是非常粗略的描述了WMS的一部分,Android系统非常庞大且复杂,所以不能过于深入细节,而是把握整体,了解这样做的好处以及缺点,本人也能力有限,如果文章中有错误,可以指出,互相探讨,互相学习,谢谢.
网友评论