Android創(chuàng)建窗口的過程

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分為三大類分別是:

  1. Application Window(應(yīng)用程序窗口),一般是指該窗口對(duì)應(yīng)一個(gè)Activity,由于Activity的創(chuàng)建時(shí)在AMS中完成的,因此創(chuàng)建應(yīng)用程序窗口只能在Activity中完成
  2. Sub Windwow(子窗口),必須有一個(gè)父窗口,父窗口可以是應(yīng)用類型窗口也可以是任何其他類型窗口
  3. 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 的添加、刪除、更新操作

  1. 創(chuàng)建 WindowManager.LayoutParams 來配置視圖的屬性
  2. 通過 WindowManagerImpl 的 addView 方法添加 view
  3. 轉(zhuǎn)到 WindowManagerGlobal 的 addView
  4. 實(shí)例化 ViewRootImpl
  5. 調(diào)用 ViewRootImpl 的 setView

ViewRootImpl的職責(zé):

  1. 代表View樹的根以及管理View樹
  2. 觸發(fā)View的測量、布局和繪制
  3. 輸入事件的中轉(zhuǎn)站
  4. 管理Surface
  5. 負(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)用窗口等等

來自:https://www.yuque.com/mikaelzero/blog/iw84e3

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容