原創(chuàng)內容,轉載請注明出處项戴,多謝配合。
WMS(WindowManagerService)是系統核心服務瑟啃,它職責主要包含如下幾個部分:
窗口管理和Surface管理,幾乎貫穿了之前圖形系統系列揩尸,這里相當于單獨拎出來分析下蛹屿,同時也是對之前圖形系統的知識點進行回顧。本篇先針對窗口管理部分進行梳理岩榆。
一错负、捋清幾個關系
關系1:Activity 、Window勇边、View
這部分牽扯到的是窗口視圖架構犹撒。
Activity是系統可視化交互組件,四大組件都由AMS統一管理生命周期粒褒,事實上它的職責只是生命周期的管理识颊,由設計模式的單一職責的原則,那勢必需要將Activity和其上的視圖View進行解耦奕坟,那么就引入Window的概念谊囚,它是個抽象類,對于Activity來說执赡,它的具體實現類是PhoneWindow镰踏,在Activity執(zhí)行attach的時候,會創(chuàng)建一個PhoneWindow對象沙合。PhoneWindow作為裝載根視圖DecorView的頂級容器奠伪,Activity通過setContentView實際上是調用PhoneWindow來創(chuàng)建DecorView,并解析xml布局加載到DecorView的contentView部分首懈。
關系2:WindowManager绊率、WindowManagerImpl、WindowManagerGlobal
這部分牽扯到的是應用端的窗口管理架構究履。
WindowManager是一個接口類滤否,繼承自接口ViewManager,負責窗口的管理(增最仑、刪藐俺、改)。它的實現類是WindowManagerImpl泥彤,而具體操作實際上又會交給WindowManagerGlobal來處理欲芹,它是個單例,進程唯一吟吝。WindowManagerGlobal執(zhí)行addView的方法中會傳入DecorView, 還會初始化一個ViewRootImpl菱父。WindowManagerGlobal因為是單例的,它內部會有兩個List來分別保存這兩個對象,來統一管理浙宜。
關系3:ViewRootImpl官辽、WindowManagerService
這份部分牽扯到的是具體窗口操作的binder IPC。
WindowManagerGlobal負責對DecorView和對應的ViewRootImpl進行統一管理粟瞬,而具體功能是由ViewRootImpl來處理野崇。
以addView為例,具體window是由WMS統一管理的亩钟,所以這里會進行binder IPC乓梨。
binder IPC:
IWindowSession: 應用程序通過Session與WMS通信,并且每個應用程序進程都會對應一個Session清酥。
IWindow: 作為WMS主動與應用程序通信的client端扶镀,因為不同的Window是不同的client,因此它也被作為識別window的key焰轻。
具體可以參考之前圖形系統系列文章:
Android圖形系統(一)-Window加載視圖過程
Android圖形系統(二)-DecorView布局加載流程
Android圖形系統(三)-View繪制流程
Android圖形系統(四)-Activity臭觉、Window、View關系總結
二辱志、Activity與Window關聯分析
Activity與Window聯系是非常緊密蝠筑,很多顯示相關操作需要兩者密切配合,那么如何保證他們的一致性呢揩懒?Android通過token來保證兩者的一致性校驗:
token流向簡單歸納如下:
1)new ActivityRecord的時候會new一個token與之對應什乙。
2)ApplicationThread scheduleLaunchActivity的時候,ActivityClientRecord 接收這個token已球。
3)activity.attach傳入該token臣镣。
4)setWindowManager的時候傳入該token,最終由Window的AppToken接收。
5)在WindowManagerGlobal的addView方法中智亮,執(zhí)行adjustLayoutParamsForSubWindow忆某,將WindowManager.LayoutParams wp,wp.token賦值appToken,并在之后的流程中,WindowManager.LayoutParams wp作為參數傳入WMS的addWindow方法對應attrs.token阔蛉。
6)WMS中通過WindowToken與之對應弃舒。
那么其實,Activity的token状原,Window中的token聋呢,連傳入addWindow的attrs.token,都是同一個token遭笋,都是ActivityRecord構造函數中創(chuàng)建的Token對象坝冕。這樣做保證了一致性徒探,主要體現在如下兩點:
- 將AMS中創(chuàng)建的ActivityRecord和Window掛鉤瓦呼,當前的window明確知道自己是哪一個Activity創(chuàng)建的。
- Window和AMS有聯系,同時又和WMS有關系央串,appToken則保證了這種同步機制磨澡。
三、窗口屬性與類型
WindowManagerGlobal的addView函數有個重要參數:WindowManager.LayoutParams质和,它對應有兩個重要的值:flag與type稳摄。
-flags:表示Window的屬性:
flags | 意義 |
---|---|
FLAG_NOT_FOCUSABLE | 表示Window不需要獲取焦點,也不需要接收各種輸入事件饲宿,此標記會同時啟用FLAG_NOT_TOUCH_MODAL厦酬,最終事件會直接傳遞給下層具有焦點的Window。 |
FLAG_NOT_TOUCH_MODAL | 系統會將當前Window區(qū)域以外的單擊事件傳遞給底層的Window瘫想,當前Window區(qū)域以內的單擊事件則自己處理仗阅,這個標記很重要,一般來說都需要開啟此標記国夜,否則其他Window將無法接收到單擊事件减噪。 |
FLAG_SHOW_WHEN_LOCKED | 開啟此模式可以讓Window顯示在鎖屏的界面上。 |
-type: 表示窗口的類型(具體值太多了就不一一列舉了车吹,具體可以去WindowManager的LayoutParams看詳細類型描述)筹裕,窗口類型大體上就分三類:
window類型 | 特點 | 層級范圍 | 典型window代表 |
---|---|---|---|
system window | 獨立存在 | 2000~2999 | Toast 、警告提示window窄驹、鍵盤window等 |
application window | 屬于應用的窗口 | 1~99 | 對應的就是activity朝卒、dialog的window |
sub window | 需要依附于父window,不能獨立存在 | 1000~1999 | popupWindow |
四乐埠、窗口組織方式(分組與分層)
Android采用的是層疊式的布局
這個部分邏輯主要在WMS.addWindow中扎运,這個方法非常非常重要!
分組:
子窗口與其依附的父窗口屬于同一組饮戳,共用相同的token豪治。
分層:
WindowState在WMS中對應一個具體的窗口。它有兩個重要屬性:
- mBaseLayer:它按窗口類型來決定z-order順序扯罐。
- mSubLayer:它按值的大小與正負關系來決定多個子窗口在父窗口中的前后關系负拟,以及相互之間的順序。
然后歹河,按如下流程來調整窗口的層級關系:
最終SurfaceFlinger會根據z-order順序來決定視圖的合成掩浙。