第8章 理解Window和WindowManager
8.1 Window和WindowManager
(1)Window
是抽象類,具體實現是PhoneWindow
,通過WindowManager
就可以建立Window。WindowManager是外界訪問Window的入口,但是Window的具體實現是在WindowManagerService
中,WindowManager和WindowManagerService的互動是一個IPC過程。所有的檢視例如Activity、Dialog、Toast都是附加在Window上的。
(2)通過WindowManager新增View的過程:將一個Button新增到螢幕座標為(100,300)的位置上
mFloatingButton = new Button(this); |
flags引數解析:FLAG_NOT_FOCUSABLE
:表示window不需要獲取焦點,也不需要接收各種輸入事件。此標記會同時啟用FLAG_NOT_TOUCH_MODAL
,最終事件會直接傳遞給下層的具有焦點的window;FLAG_NOT_TOUCH_MODAL
:在此模式下,系統會將window區域外的單擊事件傳遞給底層的window,當前window區域內的單擊事件則自己處理,一般都需要開啟這個標記;FLAG_SHOW_WHEN_LOCKED
:開啟此模式可以讓Window顯示在鎖屏的介面上。 [奇怪的是我刪除這個標記還是在鎖屏看到了新增的元件orz]
type引數表示window的型別,window共有三種類型:應用window,子window和系統window。應用window對應著一個Activity,子window不能獨立存在,需要附屬在特定的父window之上,比如Dialog就是子window。系統window是需要宣告許可權才能建立的window,比如Toast和系統狀態列這些都是系統window,需要宣告的許可權是<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
。
(3)window是分層的,每個window都對應著z-ordered
,層級大的會覆蓋在層級小的上面,應用window的層級範圍是1~99
,子window的層級範圍是1000~1999
,系統window的層級範圍是2000~2999
。
[注意,應用window的層級範圍並不是1~999
喲]
(4)WindowManager繼承自ViewManager
,常用的只有三個方法:addView
、updateView
和removeView
。
8.2 Window的內部機制
(1)Window是一個抽象的概念,不是實際存在的,它也是以View的形式存在。在實際使用中無法直接訪問Window,只能通過WindowManager才能訪問Window。每個Window都對應著一個View和一個ViewRootImpl
,Window和View通過ViewRootImpl來建立聯絡。
(2)Window的新增、刪除和更新過程都是IPC過程,以Window的新增為例,WindowManager的實現類對於addView
、updateView
和removeView
方法都是委託給WindowManagerGlobal
類,該類儲存了很多資料列表,例如所有window對應的view集合mViews
、所有window對應的ViewRootImpl的集合mRoots
等,之後新增操作交給了ViewRootImpl來處理,接著會通過WindowSession
來完成Window的新增過程,這個過程是一個IPC呼叫,因為最終是通過WindowManagerService
來完成window的新增的。
8.3 Window的建立過程
(1)Activity的window建立過程
1.Activity的啟動過程很複雜,最終會由ActivityThread
中的performLaunchActivity
來完成整個啟動過程,在這個方法內部會通過類載入器建立Activity的例項物件,並呼叫它的attach
方法為其關聯執行過程中所依賴的一系列上下文環境變數;
2.Activity實現了Window的Callback
介面,當window接收到外界的狀態變化時就會回撥Activity的方法,例如onAttachedToWindow
、onDetachedFromWindow
、dispatchTouchEvent
等;
3.Activity的Window是由PolicyManager
來建立的,它的真正實現是Policy
類,它會新建一個PhoneWindow
物件,Activity的setContentView
的實現是由PhoneWindow
來實現的;
4.Activity的頂級View是DecorView
,它本質上是一個FrameLayout
。如果沒有DecorView,那麼PhoneWindow會先建立一個DecorView,然後載入具體的佈局檔案並將view新增到DecorView的mContentParent
中,最後就是回撥Activity的onContentChanged
通知Activity檢視已經發生了變化;
5.還有一個步驟是讓WindowManager能夠識別DecorView,在ActivityThread
呼叫handleResumeActivity
方法時,首先會呼叫Activity的onResume方法,然後會呼叫makeVisible
方法,這個方法中DecorView真正地完成了新增和顯示過程。
ViewManager vm = getWindowManager(); |
(2)Dialog的Window建立過程
1.過程與Activity的Window建立過程類似,普通的Dialog的有一個特別之處,即它必須採用Activity的Context,如果採用Application的Context會報錯。原因是Application沒有應用token
,應用token一般是Activity擁有的。[service貌似也有token?]
(3)Toast的Window建立過程
1.Toast屬於系統Window,它內部的檢視由兩種方式指定:一種是系統預設的演示;另一種是通過setView
方法來指定一個自定義的View。
2.Toast具有定時取消功能,所以系統採用了Handler
。Toast的顯示和隱藏是IPC過程,都需要NotificationManagerService
來實現。在Toast和NMS進行IPC過程時,NMS會跨程序回撥Toast中的TN
類中的方法,TN類是一個Binder類,執行在Binder執行緒池中,所以需要通過Handler將其切換到當前傳送Toast請求所在的執行緒,所以Toast無法在沒有Looper的執行緒中彈出。
3.對於非系統應用來說,mToastQueue
最多能同時存在50
個ToastRecord
,這樣做是為了防止DOS
(Denial of Service,拒絕服務)。因為如果某個應用彈出太多的Toast會導致其他應用沒有機會彈出Toast。
其他學習資料
1.Android應用開發之(WindowManager類使用)
OK,本章結束,謝謝閱讀。