應用窗口創建
一、創建Window對象
每個應用類窗口window都對應於一個Activity對象。創建應用類窗口都需要先去創建一個Activity。
AmS決定啓動Activity時會先通知客戶端進程,每個客戶端進程都對應於一個ActivityThread對象,啓動Activity任務最後由ActivityThread完成。
以上是Window創建過程,簡單總結如下。
1.ActivityThread收到AMS啓動Activity請求,首先調用到ActivityThread.newActivity()方法,在該方法中根據類名反射生成目標Activity對象。
2.接着調用Activity.attach()方法。
(1) 在該方法中主要是做變量賦值以及最重要的調用PolicyManager.makeNewWindow()生成一個Window對象,而此處其實就是PhoneWindow對象,同時會在其PhoneWindow內部生成WindowManager.LayoutParams對象,而該對象內部type變量標示該Window類型,默認就是Application類型即應用程序窗口。
(2) 爲生成的window對象設置事件回調即Activity對象,這樣Window可以和Activity通信。
(3) 爲生成的window對象設置WindowManager對象,其實就是創建一個WindowManagerImpl對象,該對象負責管理Window中的View。WindowManagerImpl內部是一個WindowManagerGlobal類型的單例引用,所有操作實現最後交給該引用完成。賦值WindowManager到Activity內部。
注意:參數mToken傳遞。該參數原型時AmS中的HistoryRecord對象,由AMS傳遞創建Activity使用。它既是Activity的唯一標示,也是創建Window後的唯一標示。
二、爲Window添加View
爲window添加內容是開發者在Activity生命週期函數onCreate()中使用setContentView()設置的。
簡單總結如下:
1.Activity生命週期函數onCreate()中使用setContentView(),在該函數中實際調用到attach()中生成的PhoneWindow.setContentView(),接着會調用initActionBar()初始化ActionBar。
2.在PhoneWindow.setContentView()函數中
(1)先判斷mContentParent是否爲null,mContentParent是真正放置Window內容的FrameLayout,其id固定爲@android:id/content,開發者指定的layout.xml就是添加到這個Layout中顯示的。如果爲null代表還沒初始化這個PhoneWindow執行installDecor(),不爲null直接remove已加載的View。
(2)執行installDecor(),首先判斷如果mDecor爲null就去新建對象DecorView。DecorView其實就是繼承自FrameLayout的大小爲整個屏幕的ViewGroup,他是PhoneWindow的頂級ViewGroup,所有的View最終根元素就是它。接着又判斷mContentParent是否爲null,如果是則調用generateLayout()加載Window裝飾器layout,而Window裝飾器Layout=mContentParent+Window頂部裝飾(ActionBar/TitleBar)。
(3)generateLayout()通過讀取配置設置Window的FLAG特徵,以及根據開發者配置加載裝飾器Layout。獲取到指定的裝飾器Layout的id之後inflate得到View,使用DecorView將其添加。接着可以獲取mContentParent,不論是何種裝飾器Layout都有存在固定id爲@android:id/content的FrameLayout,用來加載開發者指定的Layout。
這裏的開發者配置有兩個途徑:
在Activity的onCreate()方法中獲取Window對象調用requestFeature()設置,在generateLayout()中使用getLocalFeature()獲取。
在AndroidManifest.xml中爲Activity使用android:theme=”“,在generateLayout()中使用getWindowStyle()獲取。
(4)通過上步可以獲取到用戶需要的ActionBar或者TitleBar,開始設置其對應屬性。至此installDecor()函數執行完成。
(5)通過以上初始化mContentParent、mDecorView完畢,接着就加載開發者指定的layout到mContentParent中,同時回調Activity中的函數實現。
3.最後調用Activity.initActionBar()初始化ActionBar。
以上就是應用類窗口添加View的過程。
三、添加顯示Window
在經過了創建Window對象,爲Window添加View之後就是告訴WmS添加顯示Window。
當Activity準備顯示Window時會通知AmS,經過一系列調用到Activity.makeVisible()。
在makeVisible()方法中:
1.首先獲取Activity內部的WindowManager對象wm。
2.接着調用wm的addView(),其真正實現在WIndowManagerImpl中,在該類中又真正調用到的是WindowManagerGlobal.addView()。而WindowManagerGlobal是個單例模式類,內部維護三個數組用於保存該應用程序中所擁有的窗口狀態,分別是:
View[] mViews。即Window的定級View
ViewRoot[] mRoots。即ViewRootImpl對象,mViews中每個View都對應一個ViewRootImpl對象。該對象負責Window的View所有操作。
WindowManager.LayoutParams[] mParams。每個Window對應一個佈局參數。
3.在WindowManagerGlobal.addView()主要是三個步驟
(1)查找是否已經添加過該窗口,不允許重複添加
(2)判斷是否是一個子Window如果是查找其父Window的View賦值給panelParentView。
(3)創建ViewRootImpl對象,調用其setView()方法完成真正添加
4.在ViewRootImpl.setView()中通過常量mWindowSession類型爲IWindowSession,通知WmS添加該這個窗口,傳入的是ViewRootImpl內部類W繼承自android.view.IWindow.Stub。
PhoneWindow充當一個臨時變量角色管理DecorView,其實真正通知WmS添加的是W。