Window 、 WindowManager 和 WMS
Window
Window,一個(gè)抽象類,具體的實(shí)現(xiàn)類為PhoneWindow
WindowManager
一個(gè)接口類,繼承自接口ViewManager,作用是管理Window,它的實(shí)現(xiàn)類為WindowManagerImpl
WMS
WMS(WindowsManagerService),窗口管理服務(wù),屬于system_server進(jìn)程,和應(yīng)用進(jìn)程處于不同進(jìn)程
對(duì)Window進(jìn)行添加和刪除就可以使用WindowManager,具體的工作都是由WMS來處理的,WindowManager和WMS通過Binder來進(jìn)行IPC操作
WindowManager何時(shí)創(chuàng)建
WindowManager 的實(shí)現(xiàn)類為 WindowManagerImpl,在Activity的attach被調(diào)用時(shí)
● Activity.attach
● mWindow = new PhoneWindow(...)
● mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),...);
○ WINDOW_SERVICE 對(duì)應(yīng)獲取到的 就是 new WindowManagerImpl 這是第一次實(shí)例化
○ mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); 這是第二次實(shí)例化,傳入當(dāng)前的window
窗口類型
Window的類型有很多種,比如應(yīng)用程序窗口、系統(tǒng)錯(cuò)誤窗口、輸入法窗口、PopupWindow、Toast、Dialog等等??倎韥碚f分為三大類分別是:
- Application Window(應(yīng)用程序窗口),一般是指該窗口對(duì)應(yīng)一個(gè)Activity,由于Activity的創(chuàng)建時(shí)在AMS中完成的,因此創(chuàng)建應(yīng)用程序窗口只能在Activity中完成
- Sub Windwow(子窗口),必須有一個(gè)父窗口,父窗口可以是應(yīng)用類型窗口也可以是任何其他類型窗口
- System Window(系統(tǒng)窗口),不需要對(duì)應(yīng)Activity,也不需要父窗口,應(yīng)用程序無權(quán)限創(chuàng)建系統(tǒng)窗口
應(yīng)用程序窗口
int FIRST_APPLICATION_WINDOW = 1;
int TYPE_BASE_APPLICATION = 1;//窗口的基礎(chǔ)值,其他的窗口值要大于這個(gè)值
int TYPE_APPLICATION = 2;//第一個(gè)應(yīng)用窗口
int TYPE_APPLICATION_STARTING = 3;//Activity啟動(dòng)時(shí),可以指定一個(gè)啟動(dòng)窗口首先顯示,直到真正的Activity窗口配置好后,刪除該窗口,顯示Activity窗口
int LAST_APPLICATION_WINDOW = 99;//最后一個(gè)應(yīng)用窗口
所有Activity默認(rèn)都是 TYPE_APPLICATION,WMS在窗口疊加時(shí),會(huì)動(dòng)態(tài)改變窗口的層值,但不會(huì)超過 99
子窗口
int FIRST_SUB_WINDOW = 1000;//子窗口類型初始值
int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4;
int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
int LAST_SUB_WINDOW = 1999;//子窗口類型結(jié)束值
子窗口的Type值范圍為1000到1999
系統(tǒng)窗口
Toast、輸入法窗口、系統(tǒng)音量條窗口、系統(tǒng)錯(cuò)誤窗口都屬于系統(tǒng)窗口
int FIRST_SYSTEM_WINDOW = 2000;//系統(tǒng)窗口類型初始值
int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;//系統(tǒng)狀態(tài)欄窗口
int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;//搜索條窗口
int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;//通話窗口
int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;//系統(tǒng)ALERT窗口
int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4;//鎖屏窗口
int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;//TOAST窗口
int LAST_SYSTEM_WINDOW = 2999;//系統(tǒng)窗口類型結(jié)束值
系統(tǒng)窗口的類型值有接近40個(gè), 系統(tǒng)窗口的Type值范圍為2000到2999
窗口顯示次序
當(dāng)一個(gè)進(jìn)程向WMS申請(qǐng)一個(gè)窗口時(shí),WMS會(huì)為窗口確定顯示次序。為了方便窗口顯示次序的管理,手機(jī)屏幕可以虛擬的用X、Y、Z軸來表示,其中Z軸垂直于屏幕,從屏幕內(nèi)指向屏幕外,這樣確定窗口顯示次序也就是確定窗口在Z軸上的次序,這個(gè)次序稱為Z-Oder
Type值是Z-Oder排序的依據(jù),我們知道應(yīng)用程序窗口的Type值范圍為1到99,子窗口1000到1999 ,系統(tǒng)窗口 2000到2999,,一般情況下,Type值越大則Z-Oder排序越靠前,就越靠近用戶
Window的標(biāo)志

系統(tǒng)窗口的添加過程
系統(tǒng)窗口的添加和Activity窗口的添加時(shí)類似的,都會(huì)通過 WindowManagerImpl 來進(jìn)行 view 的添加、刪除、更新操作
- 創(chuàng)建 WindowManager.LayoutParams 來配置視圖的屬性
- 通過 WindowManagerImpl 的 addView 方法添加 view
- 轉(zhuǎn)到 WindowManagerGlobal 的 addView
- 實(shí)例化 ViewRootImpl
- 調(diào)用 ViewRootImpl 的 setView
ViewRootImpl的職責(zé):
- 代表View樹的根以及管理View樹
- 觸發(fā)View的測量、布局和繪制
- 輸入事件的中轉(zhuǎn)站
- 管理Surface
- 負(fù)責(zé)與WMS進(jìn)行進(jìn)程間通信
在addView的過程中會(huì)判斷 WindowManagerGlobal 中的 mViews 是否存在這個(gè) view,否則拋出異常,就是我們熟悉的異常
"View " + view + " has already been added to the window manager."
在ViewRootImpl 的 setView方法中,有一個(gè)Binder的接口為IWindowSession,他的服務(wù)端是 Session,具體路徑為 frameworks/base/services/core/java/com/android/server/wm/Session.java,通過IPC傳給WMS后,addView的操作邏輯就交由WMS了,在WMS中會(huì)為這個(gè)添加的窗口分配Surface,并確定窗口顯示次序,可見負(fù)責(zé)顯示界面的是畫布Surface,而不是窗口本身。WMS會(huì)將它所管理的Surface交由SurfaceFlinger處理,SurfaceFlinger會(huì)將這些Surface混合并繪制到屏幕上
應(yīng)用(Activity)窗口的添加過程
前面分析過 WindowManager 的創(chuàng)建是在 Activity 的 attach 方法中,除了實(shí)例化之外,還會(huì)做一些接口設(shè)置工作,比如 mWindow.setCallback(this);,這樣WMS接收到的用戶消息就可以傳遞給Activity
之后在調(diào)用 handleResumeActivity 時(shí),會(huì)進(jìn)行 WindowManager 的 addView的操作,他的View是 DecorView
Dialog窗口的添加過程
和Activity基本一致,也是 new PhoneWindow() 并且設(shè)置回調(diào),不同點(diǎn)在于,Dialog調(diào)用 dimiss 的時(shí)候就會(huì)進(jìn)行 removeView的操作
Toast窗口的添加過程
其實(shí)Toast的過程也并不復(fù)雜,最終也是通過 windowManager的 addView 添加,只是Toast的創(chuàng)建過程中有許多的IPC操作
● 應(yīng)用程序調(diào)用show
● 通過IPC調(diào)用 NMS 的 show
● 封裝為ToastRecord并添加到隊(duì)列
● IPC調(diào)用到應(yīng)用程序顯示Toast
● NMS中通過Handler判斷顯示時(shí)長
● 再次IPC調(diào)用應(yīng)用程序隱藏 Toast
總結(jié)
● 窗口類型分為三種
● 窗口的添加刪除更新都是在WMS中進(jìn)行操作
● Activity和Dialog的窗口創(chuàng)建過程類似,都需要添加回調(diào)等信息
● Toast的窗口創(chuàng)建由NMS和應(yīng)用程序共同完成
● 基本流程
○ 創(chuàng)建WindowManager.LayoutParams做窗口的配置
○ 通過Context獲取WindowManager服務(wù)
○ 通過WindowManager服務(wù)來添加View等操作
● WindowManager.LayoutParams的type代表窗口類型,包括系統(tǒng)窗口,應(yīng)用窗口等等