深入理解Android中的Window和WindowManager
Window表示一個(gè)窗口的概念,Window是一個(gè)抽象類,它的具體實(shí)現(xiàn)是PhoneWindow。創(chuàng)建一個(gè)Window,需要通過(guò)WindowManager即可完成,WindowManager是外界訪問(wèn)Window的入口,Window具體實(shí)現(xiàn)位于WindowManagerService中,WindowManager和WindowManagerService的交互是一個(gè)IPC的過(guò)程。Android中,所有的視圖都是通過(guò)Window來(lái)呈現(xiàn),不管是Activity、Dialog、還是Toast,它們的視圖實(shí)際上都是附加在Window上,因此Window是實(shí)際View的直接管理者,單擊事件由Window傳遞給DecorView,然后再由DecorView傳遞給我們的View,就連Activity的設(shè)置視圖方法setContentView在底層也是通過(guò)Window來(lái)完成的。
Window和WindowManager
添加一個(gè)Window的過(guò)程,重點(diǎn)代碼是:
mWindowManager.addView(mFLoatingButton,mLayoutParams);
WindowManager.LayoutParams中有兩個(gè)flags和type參數(shù)。
Flags參數(shù)有三個(gè)Window屬性
- FLAG_NOT_FOCUSABLE。表示W(wǎng)indow不需要獲取焦點(diǎn),也不需要接收各種輸入事件,最終事件會(huì)直接傳遞給下層的具有焦點(diǎn)的Window
- FLAG_NOT_TOUCH_MODAL。在此模式下,系統(tǒng)會(huì)將當(dāng)前Window區(qū)域以外的單擊事件傳遞給底層的Window,當(dāng)前Window區(qū)域以內(nèi)的單擊事件則自己處理,這個(gè)標(biāo)記很重要,一般來(lái)說(shuō)都需要開(kāi)啟此標(biāo)記,否則其他Window將無(wú)法收到單擊事件
- FLAG_SHOW_WHEN_LOCKED。開(kāi)啟此模式可以讓W(xué)indow顯示在鎖屏的界面上。
Type參數(shù)表示W(wǎng)indow的類型,有三種類型,分別是應(yīng)用Window,子Window和系統(tǒng)Window,應(yīng)用類Window對(duì)應(yīng)一個(gè)Activity,子Window不能單獨(dú)存在,它需要附屬在特定的父Window之中,比如常見(jiàn)的Dialog就是一個(gè)子Window,系統(tǒng)Window是需要聲明權(quán)限在能創(chuàng)建的Window,比如Toast和系統(tǒng)狀態(tài)欄這些都是系統(tǒng)Window。
Window是分層的,每個(gè)Window都有對(duì)應(yīng)的z-ordered,層級(jí)大的會(huì)覆蓋在層級(jí)小的Window的上面,在三類Window中,應(yīng)用類的Window的層級(jí)范圍是1-99,子Window的層級(jí)范圍是1000-1999,系統(tǒng)Window的層級(jí)的范圍是2000-2999,這些層級(jí)范圍對(duì)應(yīng)著WindowManager.LayoutParams的Type參數(shù)。如想要Window位于所有Window的最頂層,那么采用較大的層級(jí)即可。很顯然系統(tǒng)Window層級(jí)是最大的,而且系統(tǒng)層級(jí)有很多值。
WindowManager所提供的功能很簡(jiǎn)單,常用有三個(gè)方法,即添加View,更新View和刪除View,這三個(gè)方法定義在ViewManager中,而WindowManager繼承了ViewManager。
Window的內(nèi)部機(jī)制
Window是一個(gè)抽象的概念,每一個(gè)Window都對(duì)應(yīng)著一個(gè)View和一個(gè)ViewRootImpl,Window和View通過(guò)ViewRootImpl來(lái)建立聯(lián)系,說(shuō)明View才是Window存在的實(shí)體,在實(shí)際使用中無(wú)法直接訪問(wèn)Window,對(duì)Window的訪問(wèn)必須通過(guò)WindowManager。
Window的添加過(guò)程
Window的添加過(guò)程需要通過(guò)WindowManager的addView來(lái)實(shí)現(xiàn),WindowManager是一個(gè)接口,它的真正實(shí)現(xiàn)是WindowManagerImpl類。
@Override
public void addView(View view,ViewGroup.LayoutParams params){
mGlobal.addView(view,params,mDisplay,mParentWindow);
}
@Override
public void updateViewLayout(View view,ViewGroup.LayoutParams params){
mGlobal.updateViewLayout(view,params);
}
@Override
public void removeView(View view){
mGlobal.removeView(view,false);
}
可以看到,WindowManagerImpl并沒(méi)有直接實(shí)現(xiàn)Window的三大操作,而是全部交給了WindowManagerGlobal來(lái)處理,WindowManagerGlobal以工廠的形式向外提供自己的實(shí)例。WindowManagerGlobal的addView方法主要分為如下幾步:
- 檢查參數(shù)是否合法,如果是子Window那么還需要調(diào)整一些布局參數(shù)
- 創(chuàng)建ViewRootImpl并將View添加到列表中
- 通過(guò)ViewRootImpl來(lái)更新界面并完成Window的添加過(guò)程
Window的刪除過(guò)程
Window的刪除過(guò)程和添加過(guò)程一樣,都是先通過(guò)WindowManagerImpl后,在進(jìn)一步通WindowManagerGlobal來(lái)實(shí)現(xiàn)的。里面用到一個(gè)dispatchDetachedFromWindow方法內(nèi)部實(shí)現(xiàn),這個(gè)方法主要做了四件事:
垃圾回收相關(guān)的工作,比如清除數(shù)據(jù)和消息、移除回調(diào)
通過(guò)Session的remove方法刪除Window
調(diào)用View的dispatchDetachedFromWindow方法,在內(nèi)部會(huì)調(diào)用View的onDetachedFromWindow()以及onDetachedFromWindowInternal()
調(diào)用WindowManagerGlobal的doRemoveView方法刷新數(shù)據(jù)
Window的更新過(guò)程
主要是用到updateViewLayout方法,首先它需要更新View的LayoutParams并替換掉老的LayoutParams,接著再更新ViewRootImpl中的LayoutParams,這一步是通過(guò)ViewRootImpl的setLayoutParams方法來(lái)實(shí)現(xiàn)的。在ViewRootImpl中會(huì)通過(guò)scheduleTraversals方法對(duì)View進(jìn)行重新布局,包括測(cè)量、布局、重繪這三個(gè)過(guò)程。
Window的創(chuàng)建過(guò)程
View是Android中的視圖呈現(xiàn)方式,但是View不能單獨(dú)存在,它必須附著在Window這個(gè)抽象的概念上面,因此有視圖的地方就有Window。
Activity的Window創(chuàng)建過(guò)程
如何創(chuàng)建,需要了解Activity啟動(dòng)過(guò)程,比較復(fù)雜,但它最終由ActivityThred中的perfromLaunchActivity()來(lái)完成整個(gè)啟動(dòng)過(guò)程,在這個(gè)方法內(nèi)部會(huì)通過(guò)類加載器創(chuàng)建Activity的實(shí)例對(duì)象,并調(diào)用其attach方法為其關(guān)聯(lián)運(yùn)行過(guò)程中所依賴的一系列上下文環(huán)境變量。
在Activity的attach方法里,系統(tǒng)會(huì)創(chuàng)建Activity所屬的Window對(duì)象并為其設(shè)置回調(diào)接口,Window對(duì)象的創(chuàng)建是通過(guò)PolicyManager的makeNewWindow方法實(shí)現(xiàn)的,對(duì)于Activity的setContentView的實(shí)現(xiàn)可以看出,Activity將具體實(shí)現(xiàn)交給了Window處理,而Window的具體實(shí)現(xiàn)是PhoneWindow,所以只需要看PhoneWindow相關(guān)邏輯即可,大致以下幾個(gè)步驟:
- 如果沒(méi)有DecorView,那么就創(chuàng)建它。DecorView是一個(gè)FrameLayout,是Activity的頂級(jí)View,一般來(lái)說(shuō)它的內(nèi)部包含標(biāo)題欄和內(nèi)部欄。
- 將View添加到DecorView的mContentParent中。
- 回調(diào)Activity的onContentChanged方法通知Activity視圖已經(jīng)發(fā)生改變。Activity的onContentChanged是一個(gè)空實(shí)現(xiàn)。
經(jīng)過(guò)上面三個(gè)步驟,DecorView已經(jīng)被創(chuàng)建初始化完畢,Activity的布局文件已經(jīng)成功添加到了DecorView的mContentParent中,但是這個(gè)時(shí)候DecorView還沒(méi)有被WindowManager正式添加到Window中,真正被視圖調(diào)用是在Activity的onResume方法,接著會(huì)調(diào)用Activity的makeVisible(),正是在makeVisible方法中,DecorView真正地完成了添加和顯示這兩個(gè)過(guò)程。
Dialog的Window創(chuàng)建過(guò)程
Dialog的Window的創(chuàng)建過(guò)程和Activity類似,有以下幾個(gè)步驟:
- 創(chuàng)建Window。同樣是通過(guò)PolicyManager的makeNewWindow方法來(lái)完成的。
- 初始化DecorView并將Dialog的視圖添加到DecorView中。
- 將DecorView添加到Window中并顯示。在Dialog的show方法中,會(huì)通過(guò)WindowManager將DecorView添加到Window中。
普通的Dialog有一個(gè)特殊之處,那就是必須采用Activity的Context,如果采用Application的Context,就會(huì)報(bào)錯(cuò)。
Toast的Window創(chuàng)建過(guò)程
Toast和Dialog不同,它的工作過(guò)程稍微復(fù)雜。首先Toast也是基于Window來(lái)實(shí)現(xiàn)的,但是由于Toast具有定時(shí)取消這一功能,所以系統(tǒng)采用了Handler。在Toast的內(nèi)部有兩類的IPC過(guò)程,第一類是Toast訪問(wèn)NotificationManagerService,第二類是NotificationManagerService回調(diào)Toast的TN接口。
Toast屬于系統(tǒng)Window,它內(nèi)部的視圖有兩種方式指定,一種是系統(tǒng)默認(rèn)的樣式,另一種是通過(guò)setView方法來(lái)指定一個(gè)自定義View,不管如何,它們都對(duì)應(yīng)Toast的一個(gè)View類型的內(nèi)部成員mNextView。Toast提供了show和cancel分別用于顯示和隱藏Toast,它們的內(nèi)部是一個(gè)IPC過(guò)程。
以上所述是小編給大家介紹的Android中的Window和WindowManager,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Android編程實(shí)現(xiàn)獲得內(nèi)存剩余大小與總大小的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)獲得內(nèi)存剩余大小與總大小的方法,涉及Android基于ActivityManager實(shí)現(xiàn)內(nèi)存信息的操作技巧,需要的朋友可以參考下2015-12-12
Android中解決頁(yè)簽手指按下從左到右滑動(dòng)的bug
有一種方法可以阻止父層的View截獲touch事件,就是調(diào)用 getParent().requestDisallowInterceptTouchEvent(true);方法。這篇文章給大家介紹了Android中解決頁(yè)簽手指按下從左到右滑動(dòng)的bug,一起看看吧2016-10-10
Android中封裝SDK時(shí)常用的注解總結(jié)
這篇文章主要給大家總結(jié)了在Android中封裝SDK時(shí)常用的注解的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-05-05
Android?O對(duì)后臺(tái)Service限制詳解
這篇文章主要為大家介紹了Android?O對(duì)后臺(tái)Service限制詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Android通過(guò)ksoap2傳遞復(fù)雜數(shù)據(jù)類型及CXF發(fā)布的webservice詳細(xì)介紹
這篇文章主要介紹了 Android通過(guò)ksoap2傳遞復(fù)雜數(shù)據(jù)類型詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下2017-02-02
Android Studio3.6中的View Binding初探及用法區(qū)別
這篇文章主要介紹了Android 中的View Binding初探及用法區(qū)別,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03
Android開(kāi)發(fā)實(shí)現(xiàn)標(biāo)題隨scrollview滑動(dòng)變色的方法詳解
這篇文章主要介紹了Android開(kāi)發(fā)實(shí)現(xiàn)標(biāo)題隨scrollview滑動(dòng)變色的方法,涉及Android針對(duì)滑動(dòng)事件的響應(yīng)、界面布局、屬性動(dòng)態(tài)變換等相關(guān)操作技巧,需要的朋友可以參考下2017-11-11
Filter過(guò)濾器和Listener監(jiān)聽(tīng)器詳解
這篇文章主要介紹了 Filter過(guò)濾器和Listener監(jiān)聽(tīng)器詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04

