上一篇我們主要講了Ams,篇幅有限,本篇再講講Wms,即WindowManagerService,管理窗口的服務。主要負責窗口的創建、刪除、狀態等與手機交互的事情,與Ams配合使用,在SystemServer中創建,用來保持窗口層級關系方便SurfaceFlinger繪制屏幕,和傳遞窗口信息給InputManager調用InputDispatcher將輸入消息派發到頂層窗口。
Activity、View與Window的區別與聯系,View是最底層的顯示控件,Activity包含一個DecorView+Window實現類引用PhoneWindow,而Window是一個接口-用來將手勢動作轉化為Activity可識別的信號。至於什么叫窗口,每個Activity就是窗口、每個Toast也是一個窗口、每個系統彈窗同樣是一個窗口。再比如Windows操作系統的任務欄多窗口,比較Android系統當前應用的單窗口。而窗口由什么組成,狀態和界面。哈哈,聽起來是不是很簡單?也就是說你所有的操作會產生一個狀態,這個狀態會在界面上得以體現,比如后退關閉當前頁面。前言介紹有點多,接下來說重點。
1、前面講的界面是Surface,展示由SurfaceManager來管理,狀態由WindowState來管理;布局兩種層疊與平鋪,Windows的平鋪,Android的層疊;
2、布局對應兩種實現方式:獨立進程式和庫共享式。作用是用來繪制屏幕和消息處理,前者獨立后者依賴。這樣即使一個應用崩潰系統依然完好。
3、應用窗口的高度=屏幕-狀態欄,對比蘋果的屏幕-菜單欄。
4、關於焦點,一般情況下最前面的窗口獲得焦點,二般情況下系統按鍵獲得焦點,支持窗口切換、添加動畫效果。
跟View的操作差不多,Wms也有幾個動作,assignlayer給窗口分配層值越大越靠前(動態的),performlayout根據輸入法窗口、狀態欄和窗口動畫來計算可用的大小、placesurface像draw方法一樣將窗口展示在屏幕下。
介紹幾個跟Wms關聯比較緊密的類
1、WindowManagerPolicy:接口,約束Wms能干什么。
2、WindowManager:Activity通過它調用remove和addView,Wms通過Binder類型的ViewRoot以IPC方式傳給ActivityThread(UI線程),由Handler類型的ViewRoot轉成本地的一個異步調用。
3、SurfaceManager:調動SurfaceFlinger(Linux驅動)繪制屏幕,使用芯片的圖形加速器引擎完成工作
4、InputManager:獲得輸入消息,擁有Wms引用;執行時先執行InputMonitor,使用InputWindow保存尋找焦點所需信息
5、WindowState:真正的窗口,記錄大小、層值、動畫狀態;每個窗口均有一個它;WindowToken用來實現IPC交互,一個窗口只有一個,子窗口均指向它;AppWindowToken指App在Wms的token用來最終管理交互。
6、Animation:Dim和Fade,分別是變暗和漸進動畫,是窗口用的最多的效果
7、PolicyThread:WindowManagerPolicy類型,主要Wms使用異步操作的一個工具
8、Session:SufaceSession(用於向SurfaceFlinger添加刪除窗口)的包裝類,顯然用來保存渲染的緩存信息,主要有uid、pid等
9、WaterMark:作用一防篡改二加通用背景,保存在/system/etc下,格式是content%
10、VMThread:SystemServer的異步線程
Wms最重要的就是添加和刪除窗口,還是要具體講一下的,先講添加窗口
創建ViewRoot對象,調用setView方法,通過IPC執行Session中的add方法,然后addWindow;在這一步需要執行一些前置
條件判斷比如參數是否合法、窗口是否已存在、將屏幕大小給到InputManager應用輸入法牆紙窗口的attr.token和type一致;再
添加窗口相關數據,如新建WindowState(包含session、ViewRoot的W對象、隸屬窗口等)加入mWindowMap、傳遞touch
焦點等;最后執行后置判斷將窗口狀態變化反映到相關數據中,比如將焦點給予可交互的窗口、計算並重新分配層值。
接着再講一下刪除窗口,與Windows不同,用戶不能直接關閉窗口,分兩種顯性刪除直接調用WindowManager的remove方法
隱性刪除指執行finish回調隱性刪除: 先發送一個消息,通知關閉窗口,removeViewImediate負責刪除activity窗口,closeAll負責
刪除Activity相關如菜單、對話框窗口,刪除自身的Session;然后看是否執行一個動畫、嘗試把焦點轉移到另一個窗口,相當於
反向執行add過程。
接下來講講窗口大小,mContainingFrame(整屏)> mContentFrame(窗口實際)> mFrame(屏幕上顯示),使用
layoutWindowLv來計算窗口大小,如果是輸入法則是可用大小,否則情況有三:1、考慮狀態欄2、全屏3、是否排序輸入法窗體
大小;輸入法窗口僅允許被添加一次、且下面不允許有內容,調用ViewRoot.W的resize方法,一般使用下面方法,防止其獲得焦點
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
影響窗口可視狀態因素有二:1、動畫,2、是否顯示
最后SurfaceFlinger對窗口進行重繪,操作Surface窗口,對視圖View進行變換,而動畫有兩種Animation(tranlslate、scale、
rotate、alpha)對View操作進行有限變換和Tween(距離移動)對Surface操作進行變換,主要對界面進行不間斷的重繪。
多種情況下Ams會調用Wms如增刪appWindowToken、設置窗口可見、動畫切換等,少數情況下Wms會調用Ams如暫停App
切換、橫豎屏切換、殺死App等。
橫豎屏切換主要由三種情況引起:1、ActivityStack執行resumeTopActivityLocked2、Wms執行window操作3、人為旋轉
設備。
最后放出來兩張圖,activity啟動過程和停止過程:


