android平臺現(xiàn)在占據(jù)了大部分的移動設(shè)備系統(tǒng),android開發(fā)中的窗口管理不同于pc平臺的窗口。
窗口管理是android的一個核心內(nèi)容。它管理著窗口的創(chuàng)建和銷毀,布局和大小,焦點的控制等等。
窗口可以分為兩類:
一種是應(yīng)用窗口,即由具體應(yīng)用創(chuàng)建的窗口,其實其中還可以細分出父窗口和子窗口。窗口一般都會對應(yīng)一個activity。
一種是系統(tǒng)窗口,如狀態(tài)欄,這類窗口由系統(tǒng)直接通過windowManager來創(chuàng)建,和activity無關(guān)。
在這里,窗口的概念其實可以說由三部分構(gòu)成,一部分是用來描述窗口信息的,由WindowState對象表示。一個WindowState對象對應(yīng)一個窗口,它擁有繪制窗口所需要的信息。但是真正去繪制窗口需要另一部分內(nèi)容Surface來完成,最終會通過surfaceflinger完成繪圖。還有一部分就是對消息的處理,windowmanagerService把窗口信息傳遞給InputManager,這樣InputDispatcher就能根據(jù)當前窗口的狀態(tài)進行消息處理。
我們先看下整體的架構(gòu)圖,然后再來看這兩種窗口的創(chuàng)建。WindowManager和其他很多android的服務(wù)一樣,采用C/S的架構(gòu)。其中windowManagerService跑在System_server進程,作為服務(wù)端,客戶端通過ipc調(diào)用和它進行交互。
我們通過完整的應(yīng)用程序窗口創(chuàng)建流程來了解這個結(jié)構(gòu)和整個過程。我們不去糾結(jié)其中代碼的一些細枝末節(jié)的東西,通過整體和重要的東西來看。
一.客戶端部分
在客戶端,在應(yīng)用啟動的時候,ActivityThread會調(diào)用performLaunchActivity方法,去實例化一個activity,同時調(diào)用attach方法,并傳遞很多和activity相關(guān)的參數(shù)信息。其中有個比較重要的東西是一個IBinder對象token,這個token成為activity的標識,windowmanagerService可以通過這個token獲得activity當前的運行狀態(tài)。在WindowManager中會通過該token生成一個WindowToken對象,一個父窗口對應(yīng)一個WindowToken,而具有相同token的所有其子窗口都會被歸到一個WindowToken中。即如果token相同,表示他們都會在一個窗口中。還有個用來標識窗口的類AppWindowToken,繼承自WindowToken,它由activity傳過來的token生成,和Activity一一對應(yīng)。通過token,就能找到activity和window的對應(yīng)關(guān)系來。
繼續(xù)往下看,attach方法會通過代碼mWindow = PolicyManager.makeNewWindow(this)實例化一個phoneWindow對象,但是這個對象還是比較抽象的東西。在activity開始oncreate調(diào)用時,會調(diào)用setContentView方法。會去獲得之前那個phoneWIndow對象對應(yīng)的DecorView,最后通過層層窗口修飾(狀態(tài)欄等)后調(diào)用activity的makeVisible方法,在方法中通過addiew方法完成窗口的添加。
windowManager只是提供接口,用了橋接模式,真正實現(xiàn)是WindowManagerImpl類。而調(diào)用addiew方法的對象來自另一個類LocalWindowManager,它會做一些簡單檢查,再通過WindowManagerImp類的addview完成窗口添加。addview大概分四步執(zhí)行:
1.校驗該窗口是否已經(jīng)添加過了。
2.判斷窗口類型如果是子窗口,則找到它附屬的父窗口
3.new一個ViewRootImpl對象,最后調(diào)用該對象的setView方法。
setView 方法會最終會通過ipc調(diào)用IwindowSession的add方法。Session類實現(xiàn)了該方法,并最終給WindowManagerService處理?蛻舳说墓ぷ髦链司屯瓿闪。
這里說明一下ViewRootImpl類,這其實是個handler。自然的,它一部分功能就是對消息進行處理,將用戶的一些操作分發(fā)到view中。它也是view和WindowManagerService的橋梁。可以看到它通過一個會話將信息傳遞到了WindowManagerService。而WIndowManagerService也會通過IWindow接口將指令通過消息的方式發(fā)送到ViewRootImpl,ViewRootImpl處理這些消息。
二.服務(wù)端
WindowManagerService的addWindow方法主要做三部分的處理。
1.做一些合法性校驗
2.完成窗口數(shù)據(jù)的構(gòu)建
3.完成窗口創(chuàng)建后需要作出的一些調(diào)整
我們只看第二部分。首先會new一個WindowState類,該類表示一個窗口。結(jié)合WindowToken和AppWindowToken,完整的定義了一個窗口內(nèi)容。接著創(chuàng)建一個管道,用于處理消息輸入。再然后調(diào)用attach方法,創(chuàng)建和Surface相關(guān)的內(nèi)容,用于和surfaceFlinger交互。這樣,整個窗口就搭建完成了。有了WindowState類對窗口屬性的保存以及token對窗口歸屬的標識,之后就可以通過SurfaceFlinger繪制在屏幕上了。之后通過InputManager,也能處理消息和WindowManagerService之間的傳遞。保證窗口顯示內(nèi)容和用戶操作保持一致性。
當然,WindowManagerService靠近10000行的代碼完成了很多功能,因為這篇文章只會了解窗口管理的整個架構(gòu),這里不一一詳解,以后有時間可能會把一些比較有意思的內(nèi)容再看下:
1. 窗口的創(chuàng)建和刪除
2. 窗口的顯示和隱藏控制
3. Z-order順序管理
4. 焦點窗口管理
5. 輸入法窗口管理和墻紙窗口管理
6. 切換動畫
7. 系統(tǒng)消息收集和分發(fā)
現(xiàn)在,再來看開始的架構(gòu)圖,應(yīng)該就比較清晰了。