導(dǎo)語
本章的意義在于加深對四大組件工作方式的認(rèn)識肾筐,有助于加深對Android整體的體系結(jié)構(gòu)的認(rèn)識瞧挤。很多情況下憨降,只有對Android的體系結(jié)構(gòu)有一定認(rèn)識立帖,在實際開發(fā)中才能寫出優(yōu)秀的代碼。 讀者對四大組件的工作過程有一個感性的認(rèn)識并且能夠給予上層開發(fā)一些指導(dǎo)意義捏肢。
主要內(nèi)容
- 四大組件的運行狀態(tài)
- Activity的工作過程
- Service的工作過程
- BroadcastReceiver的工作過程
- ContentProvider的工作機制
具體內(nèi)容
四大組件的運行狀態(tài)
Android的四大組件除了BroadcastReceiver以外奈籽,都需要在AndroidManifest文件注冊,BroadcastReceiver可以通過代碼注冊鸵赫。調(diào)用方式上衣屏,除了ContentProvider以外的三種組件都需要借助intent。
Activity
是一種展示型組件辩棒,用于向用戶直接地展示一個界面狼忱,并且可以接收用戶的輸入信息從而進行交互,扮演的是一個前臺界面的角色一睁。Activity的啟動由intent觸發(fā)钻弄,有隱式和顯式兩種方式。一個Activity可以有特定的啟動模式者吁,finish方法結(jié)束Activity運行窘俺。
Service
是一種計算型組件,在后臺執(zhí)行一系列計算任務(wù)复凳。它本身還是運行在主線程中的瘤泪,所以耗時的邏輯仍需要單獨的線程去完成。Activity只有一種狀態(tài):啟動狀態(tài)育八。而service有兩種:啟動狀態(tài)和綁定狀態(tài)对途。當(dāng)service處于綁定狀態(tài)時,外界可以很方便的和service進行通信髓棋,而在啟動狀態(tài)中是不可與外界通信的实檀。Service可以停止, 需要靈活采用stopService和unBindService惶洲。
BroadcastReceiver
是一種消息型組件,用于在不同的組件乃至不同的應(yīng)用之間傳遞消息膳犹。
- 靜態(tài)注冊:
在清單文件中進行注冊廣播, 這種廣播在應(yīng)用安裝時會被系統(tǒng)解析, 此種形式的廣播不需要應(yīng)用啟動就可以接收到相應(yīng)的廣播恬吕。 - 動態(tài)注冊:
需要通過Context.registerReceiver()來實現(xiàn), 并在不需要的時候通過Context.unRegisterReceiver()來解除廣播. 此種形態(tài)的廣播要應(yīng)用啟動才能注冊和接收廣播. 在實際開發(fā)中通過Context的一系列的send方法來發(fā)送廣播, 被發(fā)送的廣播會被系統(tǒng)發(fā)送給感興趣的廣播接收者, 發(fā)送和接收的過程的匹配是通過廣播接收者的<intent-filter>來描述的.可以實現(xiàn)低耦合的觀察者模式, 觀察者和被觀察者之間可以沒有任何耦合. 但廣播不適合來做耗時操作。
ContentProvider
是一種數(shù)據(jù)共享型組件须床,用于向其他組件乃至其他應(yīng)用共享數(shù)據(jù)币呵。在它內(nèi)部維持著一份數(shù)據(jù)集合, 這個數(shù)據(jù)集合既可以通過數(shù)據(jù)庫來實現(xiàn), 也可以采用其他任何類型來實現(xiàn), 例如list或者map. ContentProvider對數(shù)據(jù)集合的具體實現(xiàn)并沒有任何要求.要注意處理好內(nèi)部的insert, delete, update, query方法的線程同步, 因為這幾個方法是在Binder線程池被調(diào)用。
Activity的工作過程
- Activity的所有 startActivity 重載方法最終都會調(diào)用 startActivityForResult 侨颈。
- 調(diào)用 mInstrumentation.execStartActivity.execStartActivity() 方法余赢。
- 代碼中啟動Activity的真正實現(xiàn)是由ActivityManagerNative.getDefault().startActivity()方法完成的. ActivityManagerService簡稱AMS. AMS繼承自ActivityManagerNative(), 而ActivityManagerNative()繼承自Binder并實現(xiàn)了IActivityManager這個Binder接口, 因此AMS也是一個Binder, 它是IActivityManager的具體實現(xiàn).ActivityManagerNative.getDefault()本質(zhì)是一個IActivityManager類型的Binder對象, 因此具體實現(xiàn)是AMS。
- 在ActivityManagerNative中, AMS這個Binder對象采用單例模式對外提供, Singleton是一個單例封裝類. 第一次調(diào)用它的get()方法時會通過create方法來初始化AMS這個Binder對象, 在后續(xù)調(diào)用中會返回這個對象哈垢。
- AMS的startActivity()過程:
- checkStartActivityResult () 方法檢查啟動Activity的結(jié)果( 包括檢查有無在manifest注冊)妻柒。
- Activity啟動過程經(jīng)過兩次轉(zhuǎn)移, 最后又轉(zhuǎn)移到了mStackSupervisor.startActivityMayWait()這個方法, 所屬類為ActivityStackSupervisor. 在startActivityMayWait()內(nèi)部又調(diào)用了startActivityLocked()這里會返回結(jié)果碼就是之前checkStartActivityResult()用到的。
-
方法最后會調(diào)用startActivityUncheckedLocked(), 然后又調(diào)用了ActivityStack#resumeTopActivityLocked(). 這個時候啟動過程已經(jīng)從ActivityStackSupervisor轉(zhuǎn)移到了ActivityStack類中耘分。
- 在最后的ActivityStackSupervisor. realStartActivityLocked() 中举塔,調(diào)用了app.thread.scheduleLaunchActivity() 方法。 這個app.thread是ApplicationThread 類型求泰,繼承于IApplicationThread 是一個Binder類央渣,內(nèi)部是各種啟動/停止 Service/Activity的接口。
- 在ApplicationThread中渴频, scheduleLaunchActivity() 用來啟動Activity芽丹,里面的實現(xiàn)就是發(fā)送一個Activity的消息( 封裝成 從ActivityClientRecord 對象) 交給Handler處理。這個Handler有一個簡潔的名字 H 卜朗。
- 在H的 handleMessage() 方法里拔第,通過 handleLaunchActivity() 方法完成Activity對象的創(chuàng)建和啟動,并且ActivityThread通過handleResumeActivity()方法來調(diào)用被啟動的onResume()這一生命周期方法。PerformLaunchActivity()主要完成了如下幾件事:
- 從ActivityClientRecord對象中獲取待啟動的Activity組件信息场钉。
- 通過 Instrumentation 的 newActivity 方法使用類加載器創(chuàng)建Activity對象蚊俺。
- 通過 LoadedApk 的makeApplication方法嘗試創(chuàng)建Application對象,通過類加載器實現(xiàn)( 如果Application已經(jīng)創(chuàng)建過了就不會再創(chuàng)建)逛万。
- 創(chuàng)建 ContextImpl 對象并通過Activity的 attach 方法完成一些重要數(shù)據(jù)的初始化泳猬。(ContextImpl是一個很重要的數(shù)據(jù)結(jié)構(gòu), 它是Context的具體實現(xiàn), Context中的大部分邏輯都是由ContentImpl來完成的. ContextImpl是通過Activity的attach()方法來和Activity建立關(guān)聯(lián)的,除此之外, 在attach()中Activity還會完成Window的創(chuàng)建并建立自己和Window的關(guān)聯(lián), 這樣當(dāng)Window接收到外部輸入事件收就可以將事件傳遞給Activity。)
- 通過 mInstrumentation.callActivityOnCreate(activity, r.state) 方法調(diào)用Activity的 onCreate 方法宇植。
Service的工作過程
- 啟動狀態(tài):執(zhí)行后臺計算得封。
- 綁定狀態(tài):用于其他組件與Service交互。
兩種狀態(tài)是可以共存的当纱。
Service的啟動過程
- Service的啟動從 ContextWrapper 的 startService 開始呛每。
- 在ContextWrapper中踩窖,大部分操作通過一個 ContextImpl 對象mBase實現(xiàn).
- 在ContextImpl中坡氯, mBase.startService() 會調(diào)startServiceCommon 方法,而startServiceCommon方法又會通過 ActivityManagerNative.getDefault() ( 實際上就是AMS) 這個對象來啟動一個服務(wù)。
- AMS會通過一個 ActiveService 對象( 輔助AMS進行Service管理的類箫柳,包括Service的啟動,綁定和停止等) mServices來完成啟動Service: mServices.startServiceLocked() 手形。
- 在mServices.startServiceLocked()最后會調(diào)用 startServiceInnerLocked() 方法:將Service的信息包裝成一個 ServiceRecord 對象,ServiceRecord一直貫穿著整個Service的啟動過程悯恍。通過 bringUpServiceLocked() 方法來處理库糠,bringUpServiceLocked()又調(diào)用了 realStartServiceLocked() 方法,這才真正地去啟動一個Service了涮毫。
- realStartServiceLocked()方法的工作如下:
- app.thread.scheduleCreateService() 來創(chuàng)建Service并調(diào)用其onCreate()生命周期方法瞬欧。
- sendServiceArgsLocked() 調(diào)用其他生命周期方法,如onStartCommand()罢防。
- app.thread對象是 IApplicationThread 類型艘虎,實際上就是一個Binder,具體實現(xiàn)是ApplicationThread繼承ApplictionThreadNative咒吐。
- 具體看Application對Service的啟動過程app.thread.scheduleCreateService():通過sendMessage(H.CREATE_SERVICE , s) 野建,這個過程和Activity啟動過程類似,同時通過發(fā)送消息給Handler H來完成的恬叹。
- H會接受這個CREATE_SERVICE消息并通過ActivityThread的 handleCreateService() 來完成Service的最終啟動候生。
- handleCreateService()完成了以下工作:
- 通過ClassLoader創(chuàng)建Service對象。
- 創(chuàng)建Service內(nèi)部的Context對象绽昼。
- 創(chuàng)建Application唯鸭,并調(diào)用其onCreate()( 只會有一次)。
- 通過 service.attach() 方法建立Service與context的聯(lián)系( 與Activity類似)硅确。
- 調(diào)用service的 onCreate() 生命周期方法肿孵,至此,Service已經(jīng)啟動了疏魏。
- 將Service對象存儲到ActivityThread的一個ArrayMap中停做。
Service的綁定過程
和service的啟動過程類似的:
- Service的綁定是從 ContextWrapper 的 bindService 開始。
- 在ContextWrapper中大莫,交給 ContextImpl 對象mBase.bindService()蛉腌。
- 最終會調(diào)用ContextImpl的 bindServiceCommon 方法,這個方法完成兩件事:
- 將客戶端的ServiceConnection轉(zhuǎn)化成 ServiceDispatcher.InnerConnection 對象只厘。ServiceDispatcher連接ServiceConnection和InnerConnection烙丛。這個過程通過 LoadedApk 的 getServiceDispatcher 方法來實現(xiàn),將客戶端的ServiceConnection和ServiceDispatcher的映射關(guān)系存在一個ArrayMap中羔味。
- 通過AMS來完成Service的具體綁定過程 ActivityManagerNative.getDefault().bindService()河咽。
- AMS中,bindService()方法再調(diào)用 bindServiceLocked() 赋元,bindServiceLocked()再調(diào)用 bringUpServiceLocked() 忘蟹,bringUpServiceLocked()又會調(diào)用 realStartServiceLocked() 飒房。
- AMS的realStartServiceLocked()會調(diào)用 ActiveServices 的requrestServiceBindingLocked() 方法,最終是調(diào)用了ServiceRecord對象r的 app.thread.scheduleBindService() 方法媚值。
- ApplicationThread的一系列以schedule開頭的方法狠毯,內(nèi)部都通過Handler H來中轉(zhuǎn):scheduleBindService()內(nèi)部也是通過 sendMessage(H.BIND_SERVICE , s)。
- 在H內(nèi)部接收到BIND_SERVICE這類消息時就交給 ActivityThread 的handleBindService() 方法處理:
- 根據(jù)Servcie的token取出Service對象褥芒。
- 調(diào)用Service的 onBind() 方法嚼松,至此,Service就處于綁定狀態(tài)了锰扶。
- 這時客戶端還不知道已經(jīng)成功連接Service献酗,需要調(diào)用客戶端的binder對象來調(diào)用客戶端的ServiceConnection中的 onServiceConnected() 方法,這個通過 ActivityManagerNative.getDefault().publishService() 進行坷牛。ActivityManagerNative.getDefault()就是AMS凌摄。
- AMS的publishService()交給ActivityService對象 mServices 的 publishServiceLocked() 來處理,核心代碼就一句話 c.conn.connected(r.name,service) 漓帅。對象c的類型是 ConnectionRecord 锨亏,c.conn就是ServiceDispatcher.InnerConnection對象,service就是Service的onBind方法返回的Binder對象忙干。
- c.conn.connected(r.name,service)內(nèi)部實現(xiàn)是交給了mActivityThread.post(new RunnConnection(name ,service,0)); 實現(xiàn)器予。ServiceDispatcher的mActivityThread是一個Handler,其實就是ActivityThread中的H捐迫。這樣一來RunConnection就經(jīng)由H的post方法從而運行在主線程中乾翔,因此客戶端ServiceConnection中的方法是在主線程中被回調(diào)的。
- RunConnection的定義如下:
- 繼承Runnable接口施戴, run() 方法的實現(xiàn)也是簡單調(diào)用了ServiceDispatcher的 doConnected 方法反浓。
- 由于ServiceDispatcher內(nèi)部保存了客戶端的ServiceConntion對象,可以很方便地調(diào)用ServiceConntion對象的 onServiceConnected 方法赞哗。
- 客戶端的onServiceConnected方法執(zhí)行后雷则,Service的綁定過程也就完成了。
- 根據(jù)步驟8肪笋、9月劈、10service綁定后通過ServiceDispatcher通知客戶端的過程可以說明ServiceDispatcher起著連接ServiceConnection和InnerConnection的作用。 至于Service的停止和解除綁定的過程藤乙,系統(tǒng)流程都是類似的猜揪。
BroadcastReceiver的工作過程
簡單回顧一下廣播的使用方法, 首先定義廣播接收者, 只需要繼承BroadcastReceiver并重寫onReceive()方法即可. 定義好了廣播接收者, 還需要注冊廣播接收者, 分為兩種靜態(tài)注冊或者動態(tài)注冊. 注冊完成之后就可以發(fā)送廣播了。
廣播的注冊過程
- 動態(tài)注冊的過程是從ContextWrapper#registerReceiver()開始的. 和Activity或者Service一樣. ContextWrapper并沒有做實際的工作, 而是將注冊的過程直接交給了ContextImpl來完成坛梁。
- ContextImpl#registerReceiver()方法調(diào)用了本類的registerReceiverInternal()方法而姐。
- 系統(tǒng)首先從mPackageInfo獲取到IIntentReceiver對象, 然后再采用跨進程的方式向AMS發(fā)送廣播注冊的請求. 之所以采用IIntentReceiver而不是直接采用BroadcastReceiver, 這是因為上述注冊過程中是一個進程間通信的過程. 而BroadcastReceiver作為Android中的一個組件是不能直接跨進程傳遞的. 所有需要通過IIntentReceiver來中轉(zhuǎn)一下。
- IIntentReceiver作為一個Binder接口, 它的具體實現(xiàn)是LoadedApk.ReceiverDispatcher.InnerReceiver, ReceiverDispatcher的內(nèi)部同時保存了BroadcastReceiver和InnerReceiver, 這樣當(dāng)接收到廣播的時候, ReceiverDispatcher可以很方便的調(diào)用BroadcastReceiver#onReceive()方法. 這里和Service很像有同樣的類, 并且內(nèi)部類中同樣也是一個Binder接口划咐。
- 由于注冊廣播真正實現(xiàn)過程是在AMS中, 因此跟進AMS中, 首先看registerReceiver()方法, 這里只關(guān)心里面的核心部分. 這段代碼最終會把遠(yuǎn)程的InnerReceiver對象以及IntentFilter對象存儲起來, 這樣整個廣播的注冊就完成了拴念。
廣播的發(fā)送和接收過程
廣播的發(fā)送有幾種:普通廣播钧萍、有序廣播和粘性廣播,他們的發(fā)送/接收流程是類似的丈莺,因此只分析普通廣播的實現(xiàn)。
- 廣播的發(fā)送和接收, 本質(zhì)就是一個過程的兩個階段. 廣播的發(fā)送仍然開始于ContextImpl#sendBroadcase()方法, 之所以不是Context, 那是因為Context#sendBroad()是一個抽象方法. 和廣播的注冊過程一樣, ContextWrapper#sendBroadcast()仍然什么都不做, 只是把事情交給了ContextImpl去處理送丰。
- ContextImpl里面也幾乎什么都沒有做, 內(nèi)部直接向AMS發(fā)起了一個異步請求用于發(fā)送廣播缔俄。
- 調(diào)用AMS#broadcastIntent()方法,繼續(xù)調(diào)用broadcastIntentLocked()方法器躏。
- 在broadcastIntentLocked()內(nèi)部, 會根據(jù)intent-filter查找出匹配的廣播接收者并經(jīng)過一系列的條件過濾. 最終會將滿足條件的廣播接收者添加到BroadcastQueue中, 接著BroadcastQueue就會將廣播發(fā)送給相應(yīng)廣播接收者俐载。
- BroadcastQueue#scheduleBroadcastsLocked()方法內(nèi)并沒有立即發(fā)送廣播, 而是發(fā)送了一個BROADCAST_INTENT_MSG類型的消息, BroadcastQueue收到消息后會調(diào)用processNextBroadcast()方法。
- 無序廣播存儲在mParallelBroadcasts中, 系統(tǒng)會遍歷這個集合并將其中的廣播發(fā)送給他們所有的接收者, 具體的發(fā)送過程是通過deliverToRegisteredReceiverLocked()方法實現(xiàn)登失。deliverToRegisteredReceiverLocked()負(fù)責(zé)將一個廣播發(fā)送給一個特定的接收者, 它的內(nèi)部調(diào)用了performReceiverLocked方法來完成具體發(fā)送過程遏佣。
- performReceiverLocked()方法調(diào)用的ApplicationThread#scheduleRegisteredReceiver()實現(xiàn)比較簡單, 它通過InnerReceiver來實現(xiàn)廣播的接收。
- scheduleRegisteredReceiver()方法中揽浙,receiver.performReceive()中的receiver對應(yīng)著IIntentReceiver類型的接口. 而具體的實現(xiàn)就是ReceiverDispatcher$InnerReceiver. 這兩個嵌套的內(nèi)部類是所屬在LoadedApk中的状婶。
- 又調(diào)用了LoadedApk$ReceiverDispatcher#performReceive()的方法.在performReceiver()這個方法中, 會創(chuàng)建一個Args對象并通過mActivityThread的post方法執(zhí)行args中的邏輯. 而這些類的本質(zhì)關(guān)系就是:
- Args: 實現(xiàn)類Runnable。
- mActivityThread: 是一個Handler, 就是ActivityThread中的mH. mH就是ActivityThread$H. 這個內(nèi)部類H以前說過馅巷。
- 實現(xiàn)Runnable接口的Args中BroadcastReceiver#onReceive()方法被執(zhí)行了, 也就是說應(yīng)用已經(jīng)接收到了廣播, 同時onReceive()方法是在廣播接收者的主線程中被調(diào)用的膛虫。
android 3.1開始就增添了兩個標(biāo)記為. 分別是FLAG_INCLUDE_STOPPED_PACKAGES, FLAG_EXCLUDE_STOPPED_PACKAGES. 用來控制廣播是否要對處于停止的應(yīng)用起作用。
- FLAG_INCLUDE_STOPPED_PACKAGES: 包含停止應(yīng)用, 廣播會發(fā)送給已停止的應(yīng)用钓猬。
- FLAG_EXCLUDE_STOPPED_PACKAGES: 不包含已停止應(yīng)用, 廣播不會發(fā)送給已停止的應(yīng)用稍刀。
在android 3.1開始, 系統(tǒng)就為所有廣播默認(rèn)添加了FLAG_EXCLUDE_STOPPED_PACKAGES標(biāo)識。 當(dāng)這兩個標(biāo)記共存的時候以FLAG_INCLUDE_STOPPED_PACKAGES(非默認(rèn)項為主)敞曹。
應(yīng)用處于停止分為兩種:
- 應(yīng)用安裝后未運行账月。
- 被手動或者其他應(yīng)用強停。
開機廣播同樣受到了這個標(biāo)志位的影響. 從Android 3.1開始處于停止?fàn)顟B(tài)的應(yīng)用同樣無法接受到開機廣播, 而在android 3.1之前處于停止的狀態(tài)也是可以接收到開機廣播的澳迫。
ContentProvider的工作機制
ContentProvider是一種內(nèi)容共享型組件, 它通過Binder向其他組件乃至其他應(yīng)用提供數(shù)據(jù). 當(dāng)ContentProvider所在的進程啟動時, ContentProvider會同時啟動并發(fā)布到AMS中. 要注意:這個時候ContentProvider的onCreate()方法是先于Application的onCreate()執(zhí)行的,這一點在四大組件是少有的現(xiàn)象局齿。
- 當(dāng)一個應(yīng)用啟動時,入口方法是ActivityThread的main方法橄登,其中創(chuàng)建ActivityThread的實例并創(chuàng)建主線程的消息隊列项炼。
- ActivityThread的attach方法中會遠(yuǎn)程調(diào)用ActivityManagerService的attachApplication,并將ApplicationThread提供給AMS示绊,ApplicationThread主要用于ActivityThread和AMS之間的通信锭部。
- ActivityManagerService的attachApplication會調(diào)用ApplicationThread的bindApplication方法,這個方法會通過H切換到ActivityThread中去執(zhí)行面褐,即調(diào)用handleBindApplication方法拌禾。
- handleBindApplication方法會創(chuàng)建Application對象并加載ContentProvider,注意是先加載ContentProvider展哭,然后調(diào)用Application的onCreate方法湃窍。
- ContentProvider啟動后, 外界就可以通過它所提供的增刪改查這四個接口來操作ContentProvider中的數(shù)據(jù)源, 這四個方法都是通過Binder來調(diào)用的, 外界無法直接訪問ContentProvider, 它只能通過AMS根據(jù)URI來獲取到對應(yīng)的ContentProvider的Binder接口IContentProvider, 然后再通過IContentProvider來訪問ContentProvider中的數(shù)據(jù)源闻蛀。
ContentProvider的android:multiprocess屬性決定它是否是單實例,默認(rèn)值是false您市,也就是默認(rèn)是單實例觉痛。當(dāng)設(shè)置為true時,每個調(diào)用者的進程中都存在一個ContentProvider對象茵休。
當(dāng)調(diào)用ContentProvider的insert薪棒、delete、update榕莺、query方法中的任何一個時俐芯,如果ContentProvider所在的進程沒有啟動的話,那么就會觸發(fā)ContentProvider的創(chuàng)建钉鸯,并伴隨著ContentProvider所在進程的啟動吧史。
以query調(diào)用為例:
- 首先會獲取IContentProvider對象, 不管是通過acquireUnstableProvider()方法還是直接通過acquireProvider()方法, 他們的本質(zhì)都是一樣的, 最終都是通過acquireProvider方法來獲取ContentProvider。
- ApplicationContentResolver#acquireProvider()方法并沒有處理任何邏輯, 它直接調(diào)用了ActivityThread#acquireProvider()唠雕。
- 從ActivityThread中查找是否已經(jīng)存在了ContentProvider了, 如果存在那么就直接返回. ActivityThread中通過mProviderMap來存儲已經(jīng)啟動的ContentProvider對象, 這個集合的存儲類型ArrayMap mProviderMap. 如果目前ContentProvider沒有啟動, 那么就發(fā)送一個進程間請求給AMS讓其啟動項目目標(biāo)ContentProvider, 最后再通過installProvider()方法來修改引用計數(shù)贸营。
- AMS是如何啟動ContentProvider的呢?首先會啟動ContentProvider所在的進程, 然后再啟動ContentProvider. 啟動進程是由AMS#startProcessLocked()方法來完成, 其內(nèi)部主要是通過Process#start()方法來完成一個新進程的啟動, 新進程啟動后其入口方法為ActivityThread#main()方法。
- ActivityThread#main()是一個靜態(tài)方法, 在它的內(nèi)部首先會創(chuàng)建ActivityThread實例并調(diào)用attach()方法來進行一系列初始化, 接著就開始進行消息循環(huán). ActivityThread#attach()方法會將Application對象通過AMS#attachApplication方法跨進程傳遞給AMS, 最終AMS會完成ContentProvider的創(chuàng)建過程岩睁。
- AMS#attachApplication()方法調(diào)用了attachApplication(), 然后又調(diào)用了ApplicationThread#bindApplication(), 這個過程也屬于進程通信.bindApplication()方法會發(fā)送一個BIND_APPLICATION類型的消息給mH, 這是一個Handler, 它收到消息后會調(diào)用ActivityThread#handleBindApplication()方法莽使。
- ActivityThread#handlerBindApplication()則完成了Application的創(chuàng)建以及ContentProvider 可以分為如下四個步驟:
- 創(chuàng)建ContentProvider和Instrumentation。
- 創(chuàng)建Application對象笙僚。
- 啟動當(dāng)前進程的ContentProvider并調(diào)用onCreate()方法. 主要內(nèi)部實現(xiàn)是installContentProvider()完成了ContentProvider的啟動工作, 首先會遍歷當(dāng)前進程的ProviderInfo的列表并一一調(diào)用installProvider()方法來啟動他們, 接著將已經(jīng)啟動的ContentProvider發(fā)布到AMS中, AMS會把他們存儲在ProviderMap中, 這樣一來外部調(diào)用者就可以直接從AMS中獲取到ContentProvider. installProvider()內(nèi)部通過類加載器創(chuàng)建的ContentProvider實例并在方法中調(diào)用了attachInfo(), 在這內(nèi)部調(diào)用了ContentProvider#onCreate()芳肌。
- 調(diào)用Application#onCreate()。
經(jīng)過了上述的四個步驟, ContentProvider已經(jīng)啟動成功, 并且其所在的進程的Application也已經(jīng)成功, 這意味著ContentProvider所在的進程已經(jīng)完成了整個的啟動過程, 然后其他應(yīng)用就可以通過AMS來訪問這個ContentProvider了肋层。
當(dāng)拿到了ContentProvider以后, 就可以通過它所提供的接口方法來訪問它. 這里要注意: 這里的ContentProvider并不是原始的ContentProvider. 而是ContentProvider的Binder類型對象IContentProvider, 而IContentProvider的具體實現(xiàn)是ContentProviderNative和ContentProvider.Transport. 后者繼承了前者亿笤。
如果還用query方法來解釋流程: 那么最開始其他應(yīng)用通過AMS獲取到ContentProvider的Binder對象就是IContentProvider. 而IContentProvider的實際實現(xiàn)者是ContentProvider.Transport. 因此實際上外部應(yīng)用調(diào)用的時候本質(zhì)上會以進程間通信的方式調(diào)用ContentProvider.Transport的query()方法。