視窗管理是android的一個核心內容。它管理著視窗的建立和銷毀,布局和大小,焦點的控制等等。
視窗可以分為兩類:
一種是應用視窗,即由具體應用建立的視窗,其實其中還可以細分出父視窗和子視窗。視窗一般都會對應一個activity。
一種是系統視窗,如狀態列,這類視窗由系統直接通過windowManager來建立,和activity無關。
在這裡,視窗的概念其實可以說由三部分構成,一部分是用來描述視窗資訊的,由WindowState對象表示。一個WindowState對象對應一個視窗,它擁有繪製視窗所需要的資訊。但是真正去繪製視窗需要另一部分內容Surface來完成,最終會通過surfaceflinger完成繪圖。還有一部分就是對訊息的處理,windowmanagerService把視窗資訊傳遞給InputManager,這樣InputDispatcher就能根據當前視窗的狀態進行訊息處理。
我們先看下整體的架構圖,然後再來看這兩種視窗的建立。WindowManager和其他很多android的服務一樣,採用C/S的架構。其中windowManagerService跑在System_server進程,作為服務端,用戶端通過ipc調用和它進行互動。
我們通過完整的應用程式視窗建立流程來瞭解這個結構和整個過程。我們不去糾結其中代碼的一些細枝末節的東西,不去貼一堆代碼,通過整體和重要的東西來看。
一.用戶端部分
在用戶端,在應用啟動的時候,ActivityThread會調用performLaunchActivity方法,去執行個體化一個activity,同時調用attach方法,並傳遞很多和activity相關的參數資訊。其中有個比較重要的東西是一個IBinder對象token,這個token成為activity的標識,windowmanagerService可以通過這個token獲得activity當前的運行狀態。在WindowManager中會通過該token產生一個WindowToken對象,一個父視窗對應一個WindowToken,而具有相同token的所有其子視窗都會被歸到一個WindowToken中。即如果token相同,表示他們都會在一個視窗中。還有個用來標識視窗的類AppWindowToken,繼承自WindowToken,它由activity傳過來的token產生,和Activity一一對應。通過token,就能找到activity和window的對應關係了。
繼續往下看,attach方法會通過代碼mWindow = PolicyManager.makeNewWindow(this)執行個體化一個phoneWindow對象,但是這個對象還是比較抽象的東西。在activity開始oncreate調用時,會調用setContentView方法。會去獲得之前那個phoneWIndow對象對應的DecorView,最後通過層層視窗修飾(狀態列等)後調用activity的makeVisible方法,在方法中通過addiew方法完成視窗的添加。
windowManager只是提供介面,用了橋接模式,真正實現是WindowManagerImpl類。而調用addiew方法的對象來自另一個類LocalWindowManager,它會做一些簡單檢查,再通過WindowManagerImp類的addview完成視窗添加。addview大概分三步執行:
1.校正該視窗是否已經添加過了。
2.判斷視窗類別型如果是子視窗,則找到它附屬的父視窗
3.new一個ViewRootImpl對象,最後調用該對象的setView方法。
setView 方法會最終會通過ipc調用IwindowSession的add方法。Session類實現了該方法,並最終給WindowManagerService處理。用戶端的工作至此就完成了。
這裡說明一下ViewRootImpl類,這其實是個handler。自然的,它一部分功能就是對訊息進行處理,將使用者的一些操作分發到view中。它也是view和WindowManagerService的橋樑。可以看到它通過一個會話將資訊傳遞到了WindowManagerService。而WIndowManagerService也會通過IWindow介面將指令通過訊息的方式發送到ViewRootImpl,ViewRootImpl處理這些訊息。
二.服務端
WindowManagerService的addWindow方法主要做三部分的處理。
1.做一些合法性校正
2.完成視窗資料的構建
3.完成視窗建立後需要作出的一些調整
我們只看第二部分。首先會new一個WindowState類,該類表示一個視窗。結合WindowToken和AppWindowToken,完整的定義了一個視窗內容。接著建立一個管道,用於處理訊息輸入。再然後調用attach方法,建立和Surface相關的內容,用於和surfaceFlinger互動。這樣,整個視窗就搭建完成了。有了WindowState類對視窗屬性的儲存以及token對視窗歸屬的標識,之後就可以通過SurfaceFlinger繪製在螢幕上了。之後通過InputManager,也能處理訊息和WindowManagerService之間的傳遞。保證視窗顯示內容和使用者操作保持一致性。
當然,WindowManagerService靠近10000行的程式碼完成了很多功能,因為這篇文章只會瞭解視窗管理的整個架構,這裡不一一詳解,以後有時間可能會把一些比較有意思的內容再看下:
1. 視窗的建立和刪除
2. 視窗的顯示和隱藏控制
3. Z-order順序管理
4. 焦點視窗管理
5. IME視窗管理和牆紙視窗管理
6. 切換動畫
7. 系統訊息收集和分發
現在,再來看開始的架構圖,應該就比較清晰了。