要了解這三者之間的關(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ù)上的幫助以及生活上的快樂。嘿嘿~唯一的私心就是 希望你能喜歡我們咯堂淡。
大哥馋缅,我先敬你一瓶,先干為盡