Window和WMS

1.Window與WindowManager

Window是一個(gè)抽象類,==它的具體實(shí)現(xiàn)是PhoneWindow==,==Window創(chuàng)建時(shí)通過WindowManager完成==。
WindowManager與WindowManagerService交互是一個(gè)IPC過程。

Flags--Window屬性
  • FLAG_NOT_FOCUSABLE--表示當(dāng)前Window不需要焦點(diǎn),也不需要接收事件,事件將傳遞給下層具有焦點(diǎn)的window。
  • FLAG_NOT_TOUCH_MODAL--系統(tǒng)會(huì)將window區(qū)域以外的單擊事件傳遞給底層的window,當(dāng)前window區(qū)域以內(nèi)的單擊事件則自己處理,這個(gè)標(biāo)記很重要,一般都要開啟。
  • FLAG_SHOW_WHEN_LOCKED--可以讓window顯示在鎖屏的界面上。
Type--Window類型
  • 應(yīng)用window--對(duì)應(yīng)著一個(gè)Activity
  • 子window -- 需要附屬在特定的父window之中,Dialog
  • 系統(tǒng)window--需要聲明權(quán)限才能創(chuàng)建的Window,Toast、系統(tǒng)狀態(tài)欄

每個(gè)window對(duì)應(yīng)z-ordered,==層級(jí)大的會(huì)覆蓋在層級(jí)小的window上面==。其中應(yīng)用Window的層級(jí)范圍1-99,子Window的層級(jí)范圍是1000-1999,系統(tǒng)Window的層級(jí)范圍是2000-2999

Window和WM、WMS

  • Window是一個(gè)抽象概念,==每個(gè)Window都對(duì)應(yīng)著一個(gè)View和一個(gè)ViewRootImpl,Window和View通過ViewRootImpl來建立聯(lián)系==,因此==Window并不是實(shí)際存在的,它是以View的形式存在的==。

  • PhoneWindow是唯一實(shí)現(xiàn)Window的類,它將DecorView設(shè)為根View,每個(gè)Activity都有一個(gè)PhoneWindow對(duì)象。==PhoneWindow是Activity和View系統(tǒng)交互的橋梁==。

  • 在setContentView中,其實(shí)是通過Activity中間代理了一層,最終還是會(huì)調(diào)用到PhoneWindow。mContentParent為空時(shí)表示當(dāng)?shù)谝淮螘r(shí),當(dāng)前內(nèi)容未放置到窗口,便調(diào)用了installDecor方法。installDecore方法就是用來添加DecorView根View的。mLayoutInflater.inflate(layoutResID, mContentParent);的將layoutResID關(guān)聯(lián)的View添加到DecorView中去。最后還有就是通過onContentChanged方法回調(diào)通知Activity。

  • ==WindowManager是外界訪問Window的入口==,它是一個(gè)接口,它繼承于ViewManager。==負(fù)責(zé)Window的管理工作,實(shí)現(xiàn)類是WindowManagerImpl,而添加、更新、刪除這三個(gè)對(duì)View的操作交由WindowManagerGlobal來處理==。

  • ViewManager一個(gè)接口,它是用來添加和移除activity中View的接口,它定義了一組操作View的方法:add、update、remove。

  • WindowManagerImpl是WindowManager的實(shí)現(xiàn)類,實(shí)質(zhì)上它沒干什么事情,可以理解成是一個(gè)代理,它有一個(gè)WindowManagerGlobal的單例對(duì)象,所有事情都是由WindowManagerGlobal來處理的,也是真正處理View的添加、更新、刪除的地方。

  • WindowManagerService
    WindowManagerService是一個(gè)系統(tǒng)服務(wù),運(yùn)行在單獨(dú)的線程中,管理系統(tǒng)中所有的Window,注意是所有。在Window的添加、更新和刪除過程中,其實(shí)就是WindowManager和WindowManagerService的IPC調(diào)用中完成。

Window的添加過程、刪除過程、更新過程

在addview過程中,調(diào)用了ViewRootImpl的setView方法,View的繪制就是由它來完成的。
mWindowSession是一個(gè)IWindowSession接口,它是一個(gè)Binder對(duì)象,真正的實(shí)現(xiàn)類是Session,這也就是之前提到的IPC過程,然后在 Session 內(nèi)部會(huì)通過 WindowManagerService的addWindow 來實(shí)現(xiàn) Window 的添加。整個(gè)過程, Window 的添加請(qǐng)求移交給 WindowManagerService 去處理了 。

image.png

Activity 的 Window 創(chuàng)建過程

在了解了 Window 的概念及意義后,我們自然就清楚 Activity 的 Window 創(chuàng)建時(shí)機(jī),Window 本質(zhì)就是一塊顯示區(qū)域,==所以關(guān)于 Activity 的 Window 創(chuàng)建應(yīng)該發(fā)生在 Activity 的啟動(dòng)過程==,Activity 的啟動(dòng)過程很復(fù)雜,最終會(huì)由 ActivityThread 中的 performLaunchActivity() 來完成整個(gè)啟動(dòng)過程,在這個(gè)方法內(nèi)部會(huì)通過類加載器創(chuàng)建 Activity 的實(shí)例對(duì)象,并調(diào)用其 attach 方法為其關(guān)聯(lián)運(yùn)行過程中所依賴的一系列上下文環(huán)境變量。

==Activity 的 Window 創(chuàng)建就發(fā)生在 attach 方法里==,系統(tǒng)會(huì)創(chuàng)建 Activity 所屬的 Window 對(duì)象并為其設(shè)置回調(diào)接口,代碼如下:

mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
...

可以看到,== Window 對(duì)象的創(chuàng)建是通過 PolicyManager 的 makeNewWindow 方法實(shí)現(xiàn)的==,由于 Activity 實(shí)現(xiàn)了 Window 的 Callback 接口,因此當(dāng) Window 接受到外界的狀態(tài)改變時(shí)就會(huì)回調(diào) Activity 的方法。Callback 接口中的方法很多,有幾個(gè)是我們非常熟悉的,如 onAttachedToWindow、onDetachedFromWindow、dispatchTouchEvent 等等。

再回到 Window 的創(chuàng)建,可以看到 ==Activity 的 Window 是通過 PolicyManager 的一個(gè)工廠方法來創(chuàng)建的,但是在 PolicyManager 的實(shí)際調(diào)用中,PolicyManager 的真正實(shí)現(xiàn)是 Policy 類==,Policy 類中的 makeNewWindow 方法的實(shí)現(xiàn)如下:

public Window  makeNewWindow(Context context){
   return new PhoneWindow(context);
}

可以看出,Window 的具體實(shí)現(xiàn)類的確是 PhoneWindow。到這里 Window 已經(jīng)創(chuàng)建完成了,下面分析 ==Activity 的視圖是怎么附屬到 Window 上的==,而 Activity 的視圖由 setContentView 提供,所以從 setContentView 入手,它的源碼如下:

public void setContentView(int layoutResID){
   getWindow().setContentView(layoutResID);
   initWindowDecorActionBar();
}

可以看到,Activity 將具體實(shí)現(xiàn)交給了 Window,而 Window 的具體實(shí)現(xiàn)是 PhoneWindow,所以只需要看 PhoneWindow 的相關(guān)邏輯即可,它的處理步驟如下:

(1)、如果沒有 DecorView 就創(chuàng)建一個(gè)

DecorView 是 Activity 中的頂級(jí) View,是一個(gè) FrameLayout,一般來說它的內(nèi)部包含標(biāo)題欄和內(nèi)容欄,但是這個(gè)會(huì)隨著主題的變化而改變,不管怎么樣,內(nèi)容欄是一定存在的,并且有固定的 id:”android.R.id.content”,在 PhoneWindow 中,通過 generateDecor 方法創(chuàng)建 DecorView,通過 generateLayout 初始化主題有關(guān)布局。

(2)、將 View 添加到 DecorView 的 mContentParent 中

這一步較為簡單,直接將 Activity 的視圖添加到 DecorView 的 mContentParent 中即可,由此可以理解 Activity 的 setContentView 這個(gè)方法的來歷了,為什么不叫 setView 呢?因?yàn)?Activity 的布局文件只是被添加到 DecorView 的 mContentParent 中,因此叫 setContentView 更加具體準(zhǔn)確。

(3)、回調(diào) Activity 的 onContentChanged 方法通知 Activity 視圖已經(jīng)發(fā)生改變

前面分析到 Activity 實(shí)現(xiàn)了 Window 的 Callback 接口,這里當(dāng) Activity 的視圖已經(jīng)被添加到 DecorView 的 mContentParent 中了,需要通知 Activity,使其方便做相關(guān)的處理。

==經(jīng)過上面的三個(gè)步驟,DecorView 已經(jīng)被創(chuàng)建并初始化完畢,Activity 的布局文件也已經(jīng)成功添加到了 DecorView 的 mContentParent 中==,但是這個(gè)時(shí)候 DecorView 還沒有被 WindowManager 正式添加到 Window 中。在 ActivityThread 的 handleResumeActivity 方法中,首先會(huì)調(diào)用 Acitivy 的 onResume 方法,接著會(huì)調(diào)用 Acitivy 的 makeVisible() 方法,正是==在 makeVisible 方法中,DecorView 才真正的完成了顯示過程==,到這里 Activity 的視圖才能被用戶看到,如下:

void makeVisible(){
   if(!mWindowAdded){
      ViewManager wm = getWindowManager();
      wm.addView(mDecor, getWindow().getAttributes());
      mWindowAdded = true;
   }
   mDecor.setVisibility(View.VISIBLE);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,791評(píng)論 6 545
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,795評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,943評(píng)論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,057評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,773評(píng)論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,106評(píng)論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,082評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,282評(píng)論 0 291
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,793評(píng)論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,507評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,741評(píng)論 1 375
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,220評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,929評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,325評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,661評(píng)論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,482評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,702評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容