Activity躯泰、View、Window的理解一篇文章就夠了

要了解這三者之間的關(guān)系华糖,我們帶著問題通過分析源碼一步一步來揭開它們的神秘面紗麦向!
文章有點長,首先要理解Activity客叉、View诵竭、Window话告,我提出了一些問題,這篇文章可以解答如下問題:
1卵慰、為什么要設(shè)計Activity沙郭、View、Window裳朋?
2病线、Activity工作過程是什么樣的?(理解Activity)
3鲤嫡、Window是什么送挑?它的職能是什么?
4暖眼、View跟Window有什么聯(lián)系惕耕?
5、Activity罢荡、View赡突、Window三者如何關(guān)聯(lián)?

1区赵、為什么要設(shè)計Activity、View浪南、Window笼才?

用一句話來聯(lián)系他們之間的關(guān)系:

Activity就像工匠,Window就像是窗戶络凿,View就像是窗花骡送,LayoutInflater像剪刀,Xml配置像窗花圖紙絮记。
Android根據(jù)他們不同的職能讓他們各斯其活摔踱,同時也相互配合展示給我們靈活、精致的界面怨愤。

一張圖理清所有層級關(guān)系:



好了派敷,接下來一步一步的分析,首先從大家最熟悉的Activity開始:

我們的工匠大神Activity

一個應(yīng)用程序里所有的界面展示都來自于Activity撰洗,那Activity是如何工作的呢篮愉?
Activity工作過程:
要了解Activity工作過程,首先從啟動開始差导,下面沒有貼源碼试躏,因為本文章主題是三者之間的關(guān)系,而Activity東西太多了设褐,就簡單的講一下颠蕴。
啟動:
從startActivity開始泣刹,它會調(diào)用到Instrumentation,然后Instrumentation通過Binder向AMS(ActivityManagerService)發(fā)請求犀被,通過PIC啟動Activity椅您。而這個AIDL操作的方法定義在ApplicationThread中(里面包括了Activity所有的生命周期方法的調(diào)用)。然后通過Handle回到主線程啟動activity弱判。
因為中間流程太多襟沮,詳細(xì)寫出來容易造成“見其樹木,而不見其森林”的局面昌腰。

啟動Activity所執(zhí)行的操作:
1开伏、從ActivityClientRecord中獲取待啟動的Activity組件信息
2、通過Instrumentation的newActivity方法使用類加載器創(chuàng)建Activity對象
3遭商、通過LoadedApk的mackApplication方法來嘗試創(chuàng)建Application對象(如果Application已經(jīng)創(chuàng)建固灵,則不會重復(fù)創(chuàng)建)
4、創(chuàng)建ContextImpl對象劫流,并通過Activity的attach方法來完成一些重要數(shù)據(jù)的初始化(包括讓Activity跟Window關(guān)聯(lián))
5巫玻、調(diào)用Activity的onCreate方法

Activity其他生命周期的調(diào)用都是通過Binder向AMS發(fā)請求,然后執(zhí)行的PIC操作祠汇,最后從ApplicationThread對生命周期調(diào)用仍秤。
下面是重點:Activity、View可很、Window三者的關(guān)系诗力。

美麗的窗花View

View如何跟Activity關(guān)聯(lián)起來的?
其實View并不是直接跟Activity關(guān)聯(lián)起來的我抠,而是通過Window這個中間人苇本。如前面所說,View只是窗花菜拓,Window才是直接關(guān)聯(lián)到Activity上的瓣窄。那么:
View如何跟Window關(guān)聯(lián)起來呢?

下面先了解一下Window纳鼎,就可以理解這個問題了

靈活的窗戶Window

Window如何跟Activity關(guān)聯(lián)俺夕?
每一個Activity都包含了唯一一個PhoneWindow,這個就是Activity根Window(之所以是說根Window是因為在它上面可以增加更多其他的Window喷橙,例如:彈出框(dialog))

那么啥么,PhoneWindow如何跟Activity關(guān)聯(lián)起來的呢?
來個最簡單的贰逾,setContentView其實就讓View與Window關(guān)聯(lián)悬荣,Window跟Activity關(guān)聯(lián)起來了。

那setContentView不是View跟Activity關(guān)聯(lián)嗎疙剑?
真相見Activity源碼:



明顯是將layout設(shè)置到Window上了氯迂,那這個 getWindow() 返回的Window是誰呢践叠? 是不是前面提及PhoneWindow?




真的是PhoneWindow嚼蚀,在 attach 的時候執(zhí)行了PhoneWindow的初始化禁灼。
提到了 activity 的 attach 方法,該方法是在執(zhí)行Activity啟動時在ActivityThread里面的performLaunchActivity調(diào)用的轿曙。performLaunchActivity里面做了很多Activity啟動過程具體的操作弄捕,例如:主題、記錄Activity棧导帝、執(zhí)行Activity onCreate 方法等守谓。

這么說來setContentView其實就是將View設(shè)置到Window上,Activity展示的其實是PhoneWindow上的內(nèi)容您单。那么其實 setContentView 實際上是調(diào)用的 getWindow().setContentView斋荞。

PhoneWindow是個什么東西?它作為Activity跟View的中間人虐秦,它做了哪些工作平酿?



首先 PhoneWindow 本身就是一個 Window。

從setContentView來分析:



這里的 mContentParent 其實是一個 ViewGroup悦陋。這么看來就簡單了蜈彼。PhoneWindow里面包含了一個ViewGroup,setContentView其實就是將layout設(shè)置到了這個ViewGroup上了俺驶。

我們再看看這張圖:



DecorView是啥柳刮?
它直接跟PhoneWindow關(guān)聯(lián)起來的,有了mContentParent痒钝,為啥還需要DecorView?
如圖所見痢毒,DecorView它不僅包含了我們自己的布局送矩,它還包含了titleBar。為啥需要哪替?結(jié)構(gòu)上的需要栋荸,更好的管理布局。

Window作為中間人凭舶,已經(jīng)關(guān)聯(lián)了Activity跟View了晌块,那么如果處理Activity跟View之間的關(guān)系呢?
是時候揭開Window這個神秘面紗了:
之前提的PhoneWindow是繼承于Window的帅霜,它是連接Activity跟View之間的橋梁匆背。所有對View的一些操作都需要借助這個橋梁。

為了更好的理解Window身冀,我們先從Dialog入手钝尸。在Activity中展示一個對話框的流程是怎樣的括享?
為啥從Dialog入手,因為它里面包含了Window珍促,而且可以直接操作Window里面的View铃辖,這樣就能了解Window是如何控制View的,以及自定義Window怎么展示到Activity上(因為了解Dialog猪叙,就知道怎么讓自定義的Window與Activity關(guān)聯(lián)了)

我們省去所有的Dialog build的方法娇斩。直接從AlertDialog.show()方法開始:



可見show()方法里面執(zhí)行了create()方法,繼續(xù)看create()方法做了什么事:

new 了一個 AlertDialog穴翩,那么跟蹤它的構(gòu)造方法看看:

AlertDialog構(gòu)造方法里面最后執(zhí)行的是這個構(gòu)造方法犬第,這里找到了亮點:
1、mWindow是啥藏否?是不是PhoneWindow?
首先AlertDialog是繼承Dialog的瓶殃,mWindow就是Dialog里面初始化的對象,看看是不是PhoneWindow副签,如果是遥椿,那么就可以猜到通過在PhoneWindow添加View就可以在Activity上展示了,因為經(jīng)過上面分析Activity是跟PhoneWindow有關(guān)聯(lián)的淆储。帶著問題繼續(xù)分析源碼:



果然如此冠场,太開心了。

2本砰、AlertController是啥碴裙?



從這兩個屬性就知道了,設(shè)置Title点额、Message的舔株。用過Dialog的人都知道他們是啥,就不多說了还棱。

既然這樣關(guān)聯(lián)起來了载慈,那么Window怎么對View操控的呢?



WindowManager是主角珍手。
在Dialog build之后就將View設(shè)置進來了办铡,繼續(xù)追蹤Dialog show()這個方法,這個方法會將View與Window相互聯(lián)系:




因為電腦屏幕大小受限琳要,就截了兩個圖寡具。

mWindowManager.addView,看到這個方法稚补,可以猜想到WindowManager是個啥玩意了童叠。



從源碼注釋可看出,WindowManager是對Window進行操作的孔厉。它可以做哪些操作拯钻?

好了帖努,真相揭曉了。Window對View的操作是通過WindowManager來處理的粪般。WindowManager提供在Window上添加View拼余、移除View、更新View的操作亩歹。
然而可見 WindowManager 其實只是一個接口匙监,真正的實現(xiàn)類是WindowManagerImpl
以addView為例,里面有點繞小作,直接忽略中間過程亭姥,最后執(zhí)行addView的是通過ViewRootImpl完成Window的添加工作的,它執(zhí)行了View的requestLayout方法顾稀,在requestLayout方法里會通過WindowSession完成Window的添加過程WindowSession是IWindowSession類型的达罗,它是一個Binder對象,因此Window的添加工作其實是一次IPC調(diào)用静秆。好了粮揉,大致流程就是如此,這樣就更新界面了抚笔。

總結(jié):
1扶认、為什么要設(shè)計Activity、View殊橙、Window辐宾?
Activity就像工匠,Window就像是窗戶膨蛮,View就像是窗花叠纹,LayoutInflater像剪刀,Xml配置像窗花圖紙。
Android根據(jù)他們不同的職能讓他們各斯其活忿偷,同時也相互配合展示給我們靈活、精致的界面。為啥這樣設(shè)計澈魄?因為這樣的結(jié)構(gòu)更好管理。就像為啥需要使用MVP丸冕、MVVM沫勿、各種設(shè)計模式一樣。

2款慨、Activity工作過程是什么樣的儒飒?
以Activity啟動過程為例,Activity啟動時是通過Binder向AMS(ActivityManagerService)發(fā)請求檩奠,通過PIC啟動Activity的桩了。

3附帽、Window是什么?它的職能是什么井誉?
Activity要管理View需要通過Window來間接管理的蕉扮。Window通過addView()、removeView()颗圣、updateViewLayout()這三個方法來管理View的喳钟。

4、View跟Window有什么聯(lián)系在岂?
View需要通過Window來展示在Activity上奔则。

5、Activity蔽午、View易茬、Window三者如何關(guān)聯(lián)?
Activity包含了一個PhoneWindow及老,而PhoneWindow就是繼承于Window的抽莱,Activity通過setContentView將View設(shè)置到了PhoneWindow上,而View通過WindowManager的addView()写半、removeView()岸蜗、updateViewLayout()對View進行管理。Window的添加過程以及Activity的啟動流程都是一次IPC的過程叠蝇。Activity的啟動需要通過AMS完成璃岳;Window的添加過程需要通過WindowSession完成。

你竟然看完了悔捶,非常感謝你的支持铃慷,希望這篇文章對你有幫助~

————2020年3月11日 更新
最近建了微信公眾號和微博,由我(卷子)和我的好朋友(櫻桃)兩只小程序媛經(jīng)營的蜕该。
我們都喜歡程序員這個呆萌的群體犁柜,我們希望能給你帶來技術(shù)上的幫助以及生活上的快樂。嘿嘿~唯一的私心就是 希望你能喜歡我們咯堂淡。
大哥馋缅,我先敬你一瓶,先干為盡


干了
哎呀呀
我的微信公眾號
我的微博
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绢淀,一起剝皮案震驚了整個濱河市萤悴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌皆的,老刑警劉巖覆履,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡硝全,警方通過查閱死者的電腦和手機栖雾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伟众,“玉大人析藕,你說我怎么就攤上這事÷咐穑” “怎么了噪径?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長数初。 經(jīng)常有香客問我找爱,道長,這世上最難降的妖魔是什么泡孩? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任车摄,我火速辦了婚禮,結(jié)果婚禮上仑鸥,老公的妹妹穿的比我還像新娘吮播。我一直安慰自己,他們只是感情好眼俊,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布意狠。 她就那樣靜靜地躺著,像睡著了一般疮胖。 火紅的嫁衣襯著肌膚如雪环戈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天澎灸,我揣著相機與錄音院塞,去河邊找鬼。 笑死性昭,一個胖子當(dāng)著我的面吹牛拦止,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播糜颠,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼汹族,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了其兴?” 一聲冷哼從身側(cè)響起鞠抑,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎忌警,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡法绵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年箕速,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片朋譬。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡盐茎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出徙赢,到底是詐尸還是另有隱情字柠,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布狡赐,位于F島的核電站窑业,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏枕屉。R本人自食惡果不足惜常柄,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望搀擂。 院中可真熱鬧西潘,春花似錦、人聲如沸哨颂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽威恼。三九已至品姓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沃测,已是汗流浹背缭黔。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蒂破,地道東北人馏谨。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像附迷,于是被迫代替她去往敵國和親惧互。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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