💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
看一下WindowState的构造函数: **WindowState.java::WindowState.WindowState()** ``` WindowState(WindowManagerService service, Sessions, IWindow c, WindowToken token, WindowState attachedWindow, int seq, WindowManager.LayoutParams a, intviewVisibility, final DisplayContent displayContent) { ...... // 为子窗口分配ZOrder if((mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW)) { // 这里的mPolicy即是WindowManagerPolicy mBaseLayer= mPolicy.windowTypeToLayerLw( attachedWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER + WindowManagerService.TYPE_LAYER_OFFSET; mSubLayer= mPolicy.subWindowTypeToLayerLw(a.type); ...... } else {// 为普通窗口分配ZOrder mBaseLayer= mPolicy.windowTypeToLayerLw(a.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER + WindowManagerService.TYPE_LAYER_OFFSET; mSubLayer= 0; ...... } ...... } ``` 窗口的显示次序由两个成员字段描述:主序mBaseLayer和子序mSubLayer。主序用于描述窗口及其子窗口在所有窗口中的显示位置。而子序则描述了一个子窗口在其兄弟窗口中的显示位置。 - 主序越大,则窗口及其子窗口的显示位置相对于其他窗口的位置越靠前。 - 子序越大,则子窗口相对于其兄弟窗口的位置越靠前。对于父窗口而言,其主序取决于其类型,其子序则保持为0。而子窗口的主序与其父窗口一样,子序则取决于其类型。从上述代码可以看到,主序与子序的分配工作是由WindowManagerPolicy的两个成员函数windowTypeToLayerLw()和subWindowTypeToLayerLw()完成的。 表4-1与表4-2列出了所有可能的窗口类型以及其主序与子序的值。 :-: 表 4-1 窗口的主序 | 窗口类型 | 主序 |窗口类型 | 主序 | | --- | --- | --- | --- | |TYPE\_UNIVERSE\_BACKGROUND | 11000 | TYPE\_WALLPAPER | 21000 | | TYPE\_PHONE | 31000 |TYPE\_SEARCH\_BAR | 41000 | | TYPE\_RECENTS\_OVERLAY |51000 | TYPE\_SYSTEM\_DIALOG | 51000 | |TYPE\_TOAST | 61000 | TYPE\_PRIORITY\_PHONE | 71000 | | TYPE\_DREAM | 81000 | TYPE\_SYSTEM\_ALERT | 91000 | |TYPE\_INPUT\_METHOD | 101000 | TYPE\_INPUT\_METHOD\_DIALOG | 111000 | | TYPE\_KEYGUARD | 121000 | TYPE\_KEYGUARD\_DIALOG | 131000 | | TYPE\_STATUS\_BAR\_SUB\_PANEL | 141000 | 应用窗口与未知类型的窗口 | 21000 | :-: 表 4-2 窗口的子序 | 子窗口类型 | 子序 | | --- | --- | | TYPE\_APPLICATION\_PANEL | 1 | | TYPE\_APPLICATION\_ATTACHED\_DIALOG | 1 | | TYPE\_APPLICATION\_MEDIA | -2 | | TYPE\_APPLICATION\_MEDIA\_OVERLAY | -1 | | TYPE\_APPLICATION\_SUB\_PANEL | 2 | >[info] **注意**: 表4-2中的MEDIA和MEDIA\_OVERLAY的子序为负值,这表明它们的显示次序位于其父窗口的后面。这两个类型的子窗口是SurfaceView控件创建的。SurfaceView被实例化后,会向WMS添加一个类型为MEDIA的子窗口,它的父窗口就是承载SurfaceView控件的窗口。这个子窗口的Surface将被用于视频回放、相机预览或游戏绘制。为了不让这个子窗口覆盖住所有的父窗口中承载的其他控件(如拍照按钮,播放器控制按钮等),它必须位于父窗口之后。 从表4-1所描述的主序与窗口类型的对应关系中可以看出,WALLPAPER类型的窗口的主序竟和APPLICATION类型的窗口主序相同,这看似有点不合常理,WALLPAPER不是应该显示在所有Acitivity之下吗?其实WALLPAPER类型的窗口是一个很不安分的角色,需要在所有的APPLICATION窗口之间跳来跳去。这是因为,有的Activity指定了android:windowShowWallpaper为true,则表示窗口要求将用户当前壁纸作为其背景。对于WMS来说,最简单的办法就是将WALLPAPER窗口放置到紧邻拥有这个式样的窗口的下方。在这种需求下,为了保证主序决定窗口顺序的原则,WALLPAPER使用了与APPLICATION相同的主序。另外,输入法窗口也是一个很特殊的情况,输入法窗口会选择输入目标窗口,并将自己放置于其上。在本章中不讨论这两个特殊的例子,WALLPAPER的排序规则将在第7章中进行介绍,而输入法的排序则留给读者自行研究。 虽然知道了窗口的主序与子序是如何分配的,不过我们仍然存有疑问:如果有两个相同类型的窗口,那么它们的主序与子序岂不是完全相同?如何确定它们的显示顺序呢?事实上,表4-1和表4-2中所描述的主序和子序仅仅是排序的依据之一,WMS需要根据当前所有同类型窗口的数量为每个窗口计算最终的现实次序。