首先需要搞清楚WindowManager是什么。
準確的說,WindowManager是一個繼承自ViewManager的接口。ViewManager定義了三個函數,分別用于添加/刪除一個控件,以及更新控件的布局。
ViewManager接口的另一個實現者是ViewGroup,它是容器類控件的基類,用于將一組控件容納到自身的區域中,這一組控件被稱為子控件。ViewGroup可以根據子控件的布局參數(LayoutParams)在其自身的區域中對子控件進行布局。
讀者可以將WindowManager與ViewGroup進行一下類比:設想WindowManager是一個ViewGroup,其區域為整個屏幕,而其中的各個窗口就是一個一個的View。WindowManager通過WMS的幫助將這些View按照其布局參數(LayoutParams)將其顯示到屏幕的特定位置。二者的核心工作是一樣的,因此WindowManager與ViewGroup都繼承自ViewManager。
接下來看一下WindowManager接口的實現者。本章最開始的例子通過Context.getSystemService(Context.WINDOW\_SERVICE)的方式獲取了一個WindowManager的實例,其實現如下:
**ContextImpl.java-->ContextImpl.getSystemService()**
```
public Object getSystemService(String name) {
// 獲取WINDOW_SERVICE所對應的ServiceFetcher
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
// 調用fetcher.getService()獲取一個實例
returnfetcher == null ? null : fetcher.getService(this);
}
```
Context的實現者ContextImpl在其靜態構造函數中初始化了一系列的ServiceFetcher來響應getSystemService()的調用并創建對應的服務實例。看一下WINDOW\_SERVICE所對應的ServiceFetcher的實現:
**ContextImpl.java-->ContextImpl.static()**
```
registerService(WINDOW_SERVICE, newServiceFetcher() {
public Object getService(ContextImpl ctx) {
// ① 獲取Context中所保存的Display對象
Display display = ctx.mDisplay;
/* ② 倘若Context中沒有保存任何Display對象,則通過DisplayManager獲取系統
**主屏幕所對應的Display對象** */
if (display == null) {
DisplayManager dm =
(DisplayManager)ctx.getOuterContext().getSystemService(
Context.DISPLAY_SERVICE);
display = dm.getDisplay(Display.DEFAULT_DISPLAY);
}
// ③ 使用Display對象作為構造函數創建一個WindowManagerImpl對象并返回
return new WindowManagerImpl(display);
}});
```
由此可見,通過Context.getSystemService()的方式獲取的WindowManager其實是WindowManagerImpl類的一個實例。這個實例的構造依賴于一個Display對象。第4章介紹過DisplayContent的概念,它在WMS中表示一塊的屏幕。而這里的Display對象與DisplayContent的意義是一樣的,也用來表示一塊屏幕。
再看一下WindowManagerImpl的構造函數:
**WindowManagerImpl.java-->WindowManagerImpl.WindowManagerImpl()**
```
publicWindowManagerImpl(Display display) {
this(display, null);
}
privateWindowManagerImpl(Display display, Window parentWindow) {
mDisplay = display;
mParentWindow = parentWindow;
}
```
其構造函數實在是出奇的簡單,僅僅初始化了mDisplay與mParentWindow兩個成員變量而已。從這兩個成員變量的名字與類型來推斷,它們將決定通過這個WindowManagerImpl實例所添加的窗口的歸屬。
說明 WindowManagerImpl的構造函數引入了一個Window類型的參數parentWindow。Window類是什么呢?以Activity為例,一個Activity顯示在屏幕上時包含了標題欄、菜單按鈕等控件,但是在setContentView()時并沒有在layout中放置它們。這是因為Window類預先為我們準備好了這一切,它們被稱之為窗口裝飾。除了產生窗口裝飾之外,Window類還保存了窗口相關的一些重要信息。例如窗口ID(IWindow.asBinder()的返回值)以及窗口所屬Activity的ID(即AppToken)。在6.6.1 介將會對這個類做詳細的介紹。
也許在WindowManagerImpl的addView()函數的實現中可以找到更多的信息。
**WindowManagerImpl.java-->WindowManagerImpl.addView()**
```
publicvoid addView(View view, ViewGroup.LayoutParams params) {
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
```
WindowManagerImpl.addView()將實際的操作委托給一個名為mGlobal的成員來完成,它隨著WindowManagerImpl的創建而被初始化:
```
privatefinal WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
```
可見mGlobal的類型是WindowManagerGlobal,而且WindowManagerGlobal是一個單例模式——即一個進程中最多僅有一個WindowManagerGlobal實例。所有WindowManagerImpl都是這個進程唯一的WindowManagerGlobal實例的代理。
此時便對WindowManager的結構體系有了一個清晰的認識,如圖6-2所示。
:-: 
圖 6 - 2 WindowManager的結構體系
- ViewManager接口:WindowManager體系中最基本的接口。WindowManager繼承自這個接口說明了WindowManager與ViewGroup本質上的一致性。
- WindowManager接口:WindowManager接口繼承自ViewManager接口的同時,根據窗口的一些特殊性增加了兩個新的接口。getDefaultDisplay()用以得知這個WindowManager的實例會將窗口添加到哪個屏幕上去。而removeViewImmediate()則要求WindowManager必須在這個調用返回之前完成所有的銷毀工作。
- WindowManagerImpl類:WindowManager接口的實現者。它自身沒有什么實際的邏輯,WindowManager所定義的接口都是交由WindowManagerGlobal完成的。但是它保存了兩個重要的只讀成員,它們分別指明了通過這個WindowManagerImpl實例所管理的窗口將被顯示在哪個屏幕上,以及將會作為哪個窗口的子窗口。因此在一個進程中,WindowManagerImpl的實例可能有多個。
- WindowManagerGlobal類:它沒有繼承上述任何一個接口,但它是WindowManager的最終實現者。它維護了當前進程中所有已經添加到系統中的窗口的信息。另外,在一個進程中僅有一個WindowManagerGlobal的實例。
在理清了WindowManager的結構體系后,便可以探討WindowManager是如何完成窗口管理的。其管理方式體現在其對ViewManager的三個接口的實現上。為了簡潔起見,我們將直接分析WindowManagerGlobal中的實現。
- 前言
- 推薦序
- 第1章 開發環境部署
- 1.1獲取Android源代碼
- 1.2Android的編譯
- 1.3在IDE中導入Android源代碼
- 1.3.1將Android源代碼導入Eclipse
- 1.3.2將Android源代碼導入SourceInsight
- 1.4調試Android源代碼
- 1.4.1使用Eclipse調試Android Java源代碼
- 1.4.2使用gdb調試Android C/C 源代碼
- 1.5本章小結
- 第2章 深入理解Java Binder和MessageQueue
- 2.1概述
- 2.2Java層中的Binder分析
- 2.2.1Binder架構總覽
- 2.2.2初始化Java層Binder框架
- 2.2.3窺一斑,可見全豹乎
- 2.2.4理解AIDL
- 2.2.5Java層Binder架構總結
- 2.3心系兩界的MessageQueue
- 2.3.1MessageQueue的創建
- 2.3.2提取消息
- 2.3.3nativePollOnce函數分析
- 2.3.4MessageQueue總結
- 2.4本章小結
- 第3章 深入理解AudioService
- 3.1概述
- 3.2音量管理
- 3.2.1音量鍵的處理流程
- 3.2.2通用的音量設置函數setStreamVolume()
- 3.2.3靜音控制
- 3.2.4音量控制小結
- 3.3音頻外設的管理
- 3.3.1 WiredAccessoryObserver 設備狀態的監控
- 3.3.2AudioService的外設狀態管理
- 3.3.3音頻外設管理小結
- 3.4AudioFocus機制的實現
- 3.4.1AudioFocus簡單的例子
- 3.4.2AudioFocus實現原理簡介
- 3.4.3申請AudioFocus
- 3.4.4釋放AudioFocus
- 3.4.5AudioFocus小結
- 3.5AudioService的其他功能
- 3.6本章小結
- 第4章 深入理解WindowManager-Service
- 4.1初識WindowManagerService
- 4.1.1一個從命令行啟動的動畫窗口
- 4.1.2WMS的構成
- 4.1.3初識WMS的小結
- 4.2WMS的窗口管理結構
- 4.2.1理解WindowToken
- 4.2.2理解WindowState
- 4.2.3理解DisplayContent
- 4.3理解窗口的顯示次序
- 4.3.1主序、子序和窗口類型
- 4.3.2通過主序與子序確定窗口的次序
- 4.3.3更新顯示次序到Surface
- 4.3.4關于顯示次序的小結
- 4.4窗口的布局
- 4.4.1從relayoutWindow()開始
- 4.4.2布局操作的外圍代碼分析
- 4.4.3初探performLayoutAndPlaceSurfacesLockedInner()
- 4.4.4布局的前期處理
- 4.4.5布局DisplayContent
- 4.4.6布局的階段
- 4.5WMS的動畫系統
- 4.5.1Android動畫原理簡介
- 4.5.2WMS的動畫系統框架
- 4.5.3WindowAnimator分析
- 4.5.4深入理解窗口動畫
- 4.5.5交替運行的布局系統與動畫系統
- 4.5.6動畫系統總結
- 4.6本章小結
- 第5章 深入理解Android輸入系統
- 5.1初識Android輸入系統
- 5.1.1getevent與sendevent工具
- 5.1.2Android輸入系統簡介
- 5.1.3IMS的構成
- 5.2原始事件的讀取與加工
- 5.2.1基礎知識:INotify與Epoll
- 5.2.2 InputReader的總體流程
- 5.2.3 深入理解EventHub
- 5.2.4 深入理解InputReader
- 5.2.5原始事件的讀取與加工總結
- 5.3輸入事件的派發
- 5.3.1通用事件派發流程
- 5.3.2按鍵事件的派發
- 5.3.3DispatcherPolicy與InputFilter
- 5.3.4輸入事件的派發總結
- 5.4輸入事件的發送、接收與反饋
- 5.4.1深入理解InputChannel
- 5.4.2連接InputDispatcher和窗口
- 5.4.3事件的發送
- 5.4.4事件的接收
- 5.4.5事件的反饋與發送循環
- 5.4.6輸入事件的發送、接收與反饋總結
- 5.5關于輸入系統的其他重要話題
- 5.5.1輸入事件ANR的產生
- 5.5.2 焦點窗口的確定
- 5.5.3以軟件方式模擬用戶操作
- 5.6本章小結
- 第6章 深入理解控件系統
- 6.1 初識Android的控件系統
- 6.1.1 另一種創建窗口的方法
- 6.1.2 控件系統的組成
- 6.2 深入理解WindowManager
- 6.2.1 WindowManager的創建與體系結構
- 6.2.2 通過WindowManagerGlobal添加窗口
- 6.2.3 更新窗口的布局
- 6.2.4 刪除窗口
- 6.2.5 WindowManager的總結
- 6.3 深入理解ViewRootImpl
- 6.3.1 ViewRootImpl的創建及其重要的成員
- 6.3.2 控件系統的心跳:performTraversals()
- 6.3.3 ViewRootImpl總結
- 6.4 深入理解控件樹的繪制
- 6.4.1 理解Canvas
- 6.4.2 View.invalidate()與臟區域
- 6.4.3 開始繪制
- 6.4.4 軟件繪制的原理
- 6.4.5 硬件加速繪制的原理
- 6.4.6 使用繪圖緩存
- 6.4.7 控件動畫
- 6.4.8 繪制控件樹的總結
- 6.5 深入理解輸入事件的派發
- 6.5.1 觸摸模式
- 6.5.2 控件焦點
- 6.5.3 輸入事件派發的綜述
- 6.5.4 按鍵事件的派發
- 6.5.5 觸摸事件的派發
- 6.5.6 輸入事件派發的總結
- 6.6 Activity與控件系統
- 6.6.1 理解PhoneWindow
- 6.6.2 Activity窗口的創建與顯示
- 6.7 本章小結
- 第7章 深入理解SystemUI
- 7.1 初識SystemUI
- 7.1.1 SystemUIService的啟動
- 7.1.2 狀態欄與導航欄的創建
- 7.1.3 理解IStatusBarService
- 7.1.4 SystemUI的體系結構
- 7.2 深入理解狀態欄
- 7.2.1 狀態欄窗口的創建與控件樹結構
- 7.2.2 通知信息的管理與顯示
- 7.2.3 系統狀態圖標區的管理與顯示
- 7.2.4 狀態欄總結
- 7.3 深入理解導航欄
- 7.3.1 導航欄的創建
- 7.3.2 虛擬按鍵的工作原理
- 7.3.3 SearchPanel
- 7.3.4 關于導航欄的其他話題
- 7.3.5 導航欄總結
- 7.4 禁用狀態欄與導航欄的功能
- 7.4.1 如何禁用狀態欄與導航欄的功能
- 7.4.2 StatusBarManagerService對禁用標記的維護
- 7.4.3 狀態欄與導航欄對禁用標記的響應
- 7.5 理解SystemUIVisibility
- 7.5.1 SystemUIVisibility在系統中的漫游過程
- 7.5.2 SystemUIVisibility發揮作用
- 7.5.3 SystemUIVisibility總結
- 7.6 本章小結
- 第8章 深入理解Android壁紙
- 8.1 初識Android壁紙
- 8.2深入理解動態壁紙
- 8.2.1啟動動態壁紙的方法
- 8.2.2壁紙服務的啟動原理
- 8.2.3 理解UpdateSurface()方法
- 8.2.4 壁紙的銷毀
- 8.2.5 理解Engine的回調
- 8.3 深入理解靜態壁紙-ImageWallpaper
- 8.3.1 獲取用作靜態壁紙的位圖
- 8.3.2 靜態壁紙位圖的設置
- 8.3.3 連接靜態壁紙的設置與獲取-WallpaperObserver
- 8.4 WMS對壁紙窗口的特殊處理
- 8.4.1 壁紙窗口Z序的確定
- 8.4.2 壁紙窗口的可見性
- 8.4.3 壁紙窗口的動畫
- 8.4.4 壁紙窗口總結
- 8.5 本章小結