一、Context與Application膳犹、Activity恬吕、Service的繼承關(guān)系
? ? ? ?在開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)遇到使用context的情況须床,如通過(guò)context得到resource铐料,通過(guò)context實(shí)現(xiàn)layoutInflater等,在代碼環(huán)境中使用context豺旬,可用通過(guò)activity钠惩、application以及service來(lái)實(shí)現(xiàn),那么這是為什么呢族阅?
? ? ? ?因?yàn)槿叨际抢^承自context抽象類的篓跛,如下圖所示:
? ? ? ?可以看到,activity是繼承自ContextThemeWrapper坦刀,而Service和Application繼承自ContextWrapper
? ? ? ?對(duì)于ContextWrapper和ContextThemeWrapper而言愧沟,兩者存在繼承關(guān)系,最終繼承自Context鲤遥,而Context實(shí)際上是一個(gè)抽象類央渣,它的實(shí)現(xiàn)是交給ContextImpl類負(fù)責(zé),所以可以先提一下渴频,app在啟動(dòng)時(shí)芽丹,application、activity和service三者能夠關(guān)聯(lián)到context卜朗,實(shí)際上都是在創(chuàng)建者三個(gè)要素的時(shí)候拔第,同時(shí)實(shí)現(xiàn)了ContextImpl對(duì)象咕村,具體證明放在之后描述。
? ? ? 知道了activity蚊俺、service和application與context的關(guān)系之后懈涛,也就理解了為什么可以把這仨當(dāng)context來(lái)用了,其實(shí)context意義為場(chǎng)景泳猬,而activity批钠、service及application從語(yǔ)義上理解也是場(chǎng)景的概念。
? ? ? 那么還有一個(gè)問(wèn)題得封,activity等著仨是如何實(shí)現(xiàn)各自context的對(duì)應(yīng)關(guān)系呢埋心,需要分析app的啟動(dòng)過(guò)程了。
二 忙上、Context與三者的對(duì)應(yīng)關(guān)系描述
? ? ? ?在app啟動(dòng)時(shí)拷呆,或者啟動(dòng)一個(gè)新的activity及service中,實(shí)際上先由AmS(Activity Manager Service)來(lái)負(fù)責(zé)疫粥,AmS在一個(gè)進(jìn)程中茬斧,啟動(dòng)的Activity或app是由另一個(gè)所在進(jìn)程ActivityThread來(lái)實(shí)現(xiàn),AmS負(fù)責(zé)管理ActivityThread中的相關(guān)具體過(guò)程梗逮,因此需要實(shí)現(xiàn)跨進(jìn)程間的數(shù)據(jù)交互项秉,而AmS和ActivityThread的數(shù)據(jù)交互入口是ActivityThread中的ApplicationThread,ApplicationThread是一個(gè)Binder變量慷彤,可以接受AmS傳遞來(lái)的數(shù)據(jù)娄蔼。
2.1 Application與Context的關(guān)系
? ? ? ?application初啟動(dòng)時(shí),對(duì)于ActivityThread中瞬欧,首先會(huì)執(zhí)行到bindApplication方法贷屎,該方法的聲明如下:
? ? ? ?在調(diào)用了bindApplication方法之后咒吐,通過(guò)傳遞來(lái)的appInfo野建,會(huì)構(gòu)建一個(gè)AppBindData類型的數(shù)據(jù),該數(shù)據(jù)構(gòu)建完成之后恬叹,會(huì)由ActivityThread的內(nèi)部Handler發(fā)送一個(gè)消息:
? ? ? ? 這里的data就是之前創(chuàng)建完成的AppBindData類型的绽昼,也是handleBindApplication的傳入?yún)?shù);info是LoadApk類型唯鸭,在老版本中info實(shí)際上就是PackageInfo這個(gè)類,所以LoadApk就是PackageInfo硅确,LoadApk這個(gè)類中有makeApplication方法目溉,在該方法中存在實(shí)現(xiàn)context和application關(guān)聯(lián)的步驟明肮,查看makeApplication方法:
? ? ? ?以上就實(shí)現(xiàn)了application的創(chuàng)建過(guò)程中實(shí)現(xiàn)context關(guān)聯(lián)的過(guò)程,再由流程圖的形式描述一下:
2.2 Activity與Context的關(guān)系
? ? ? ? activity與context的關(guān)系也類似與application的流程河咽,啟動(dòng)activity時(shí)钠右,首先也是交由AmS進(jìn)行處理,AmS會(huì)傳遞一個(gè)ActivityInfo類型的數(shù)據(jù)給ActivityThread忘蟹,然后ActivityThread拿到了該數(shù)據(jù)之后執(zhí)行后續(xù)的一系列操作飒房。ActivityInfo也是一個(gè)實(shí)現(xiàn)Parcelable接口的類型。
? ? ? ?整體流程如下:
2.3 Service與Context的關(guān)系
? ? ? ? 與上述兩種情況類似,啟動(dòng)Service(注意這里是startService而不是bindService)時(shí)坷牛,首先AmS進(jìn)行處理罕偎,包裝出一個(gè)ServiceInfo類型的數(shù)據(jù),ActivityThread接收到數(shù)據(jù)后首先執(zhí)行scheduleCreateService方法:
? ? ? ?在該方法中,首先通過(guò)getPackageInfoNoCheck得到了packageInfo對(duì)象蹂楣,根據(jù)該對(duì)象得到ClassLoader后通過(guò)反射構(gòu)建了service俏站,獲取了service對(duì)象之后,利用ContextImpl的靜態(tài)方法得到了context痊土,context設(shè)置了service為其外部代言人肄扎,之后創(chuàng)建了application,將service attach上去,最后啟動(dòng)onCreate方法犯祠。
? ? ? ?有一個(gè)疑問(wèn)萌丈,為什么在創(chuàng)建了service的過(guò)程中需要構(gòu)建application對(duì)象呢?可能是跟后臺(tái)service依舊屬于一個(gè)application雷则,雖然沒(méi)有前臺(tái)界面的展示辆雾,沒(méi)有明顯的application構(gòu)建,但是service需要依賴application月劈,所以針對(duì)無(wú)界面度迂、后臺(tái)service啟動(dòng)的情況下需要?jiǎng)?chuàng)建application為service提供attach支持。
? ? ? ?整體流程如下:
三猜揪、總結(jié)
? ? ? 通過(guò)第二部分的分析惭墓,可以總結(jié)如下:
? ? ? 不論是啟動(dòng)app還是某個(gè)activity,亦或是service而姐,最初都需要提交給AmS腊凶,AmS相當(dāng)于總負(fù)責(zé)人,總負(fù)責(zé)人處理好消息后打包成數(shù)據(jù)(ApplicationInfo拴念、ActivityInfo及ServiceInfo)钧萍,并將數(shù)據(jù)通過(guò)跨進(jìn)程傳遞的方式遞交給ActivityThread進(jìn)行處理,ActivityThread在接收時(shí)對(duì)外首先暴露ApplicationThread這個(gè)Binder接口政鼠,然后獲取到相應(yīng)的數(shù)據(jù)之后執(zhí)行創(chuàng)建application风瘦、activity及service的流程;同時(shí)在創(chuàng)建這仨時(shí)公般,通過(guò)ContextImpl的靜態(tài)方法來(lái)創(chuàng)建ContextImpl對(duì)象万搔,對(duì)象創(chuàng)建完成之后通過(guò)setOuterContext方法指定各類的外部代言人,但是該方法的參數(shù)是Context官帘,而恰好Application瞬雹、Activity及Service都繼承自Context,所有可以有效充當(dāng)contextImpl的外部代言人刽虹,來(lái)調(diào)用contextImpl中的方法酗捌,這就是application、activity及service是context的本質(zhì)状婶,本質(zhì)在于以代言人的身份調(diào)用方法(好像屬于一類設(shè)計(jì)模式?)意敛。
? ? ?多提一句馅巷,contextImpl內(nèi)的核心實(shí)現(xiàn)其實(shí)大部分都在LoadApk方法內(nèi)具體完成的膛虫。