Android 四大組件的工作過程

導(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的工作過程
  1. Activity的所有 startActivity 重載方法最終都會調(diào)用 startActivityForResult 侨颈。
  2. 調(diào)用 mInstrumentation.execStartActivity.execStartActivity() 方法余赢。
  3. 代碼中啟動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。
  4. 在ActivityManagerNative中, AMS這個Binder對象采用單例模式對外提供, Singleton是一個單例封裝類. 第一次調(diào)用它的get()方法時會通過create方法來初始化AMS這個Binder對象, 在后續(xù)調(diào)用中會返回這個對象哈垢。
  5. AMS的startActivity()過程:
    1. checkStartActivityResult () 方法檢查啟動Activity的結(jié)果( 包括檢查有無在manifest注冊)妻柒。
    2. Activity啟動過程經(jīng)過兩次轉(zhuǎn)移, 最后又轉(zhuǎn)移到了mStackSupervisor.startActivityMayWait()這個方法, 所屬類為ActivityStackSupervisor. 在startActivityMayWait()內(nèi)部又調(diào)用了startActivityLocked()這里會返回結(jié)果碼就是之前checkStartActivityResult()用到的。
    3. 方法最后會調(diào)用startActivityUncheckedLocked(), 然后又調(diào)用了ActivityStack#resumeTopActivityLocked(). 這個時候啟動過程已經(jīng)從ActivityStackSupervisor轉(zhuǎn)移到了ActivityStack類中耘分。


  6. 在最后的ActivityStackSupervisor. realStartActivityLocked() 中举塔,調(diào)用了app.thread.scheduleLaunchActivity() 方法。 這個app.thread是ApplicationThread 類型求泰,繼承于IApplicationThread 是一個Binder類央渣,內(nèi)部是各種啟動/停止 Service/Activity的接口。
  7. 在ApplicationThread中渴频, scheduleLaunchActivity() 用來啟動Activity芽丹,里面的實現(xiàn)就是發(fā)送一個Activity的消息( 封裝成 從ActivityClientRecord 對象) 交給Handler處理。這個Handler有一個簡潔的名字 H 卜朗。
  8. 在H的 handleMessage() 方法里拔第,通過 handleLaunchActivity() 方法完成Activity對象的創(chuàng)建和啟動,并且ActivityThread通過handleResumeActivity()方法來調(diào)用被啟動的onResume()這一生命周期方法。PerformLaunchActivity()主要完成了如下幾件事:
    1. 從ActivityClientRecord對象中獲取待啟動的Activity組件信息场钉。
    2. 通過 Instrumentation 的 newActivity 方法使用類加載器創(chuàng)建Activity對象蚊俺。
    3. 通過 LoadedApk 的makeApplication方法嘗試創(chuàng)建Application對象,通過類加載器實現(xiàn)( 如果Application已經(jīng)創(chuàng)建過了就不會再創(chuàng)建)逛万。
    4. 創(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。)
    5. 通過 mInstrumentation.callActivityOnCreate(activity, r.state) 方法調(diào)用Activity的 onCreate 方法宇植。

Service的工作過程

  • 啟動狀態(tài):執(zhí)行后臺計算得封。
  • 綁定狀態(tài):用于其他組件與Service交互。
    兩種狀態(tài)是可以共存的当纱。
Service的啟動過程
Service的啟動過程
  1. Service的啟動從 ContextWrapper 的 startService 開始呛每。
  2. 在ContextWrapper中踩窖,大部分操作通過一個 ContextImpl 對象mBase實現(xiàn).
  3. 在ContextImpl中坡氯, mBase.startService() 會調(diào)startServiceCommon 方法,而startServiceCommon方法又會通過 ActivityManagerNative.getDefault() ( 實際上就是AMS) 這個對象來啟動一個服務(wù)。
  4. AMS會通過一個 ActiveService 對象( 輔助AMS進行Service管理的類箫柳,包括Service的啟動,綁定和停止等) mServices來完成啟動Service: mServices.startServiceLocked() 手形。
  5. 在mServices.startServiceLocked()最后會調(diào)用 startServiceInnerLocked() 方法:將Service的信息包裝成一個 ServiceRecord 對象,ServiceRecord一直貫穿著整個Service的啟動過程悯恍。通過 bringUpServiceLocked() 方法來處理库糠,bringUpServiceLocked()又調(diào)用了 realStartServiceLocked() 方法,這才真正地去啟動一個Service了涮毫。
  6. realStartServiceLocked()方法的工作如下:
    1. app.thread.scheduleCreateService() 來創(chuàng)建Service并調(diào)用其onCreate()生命周期方法瞬欧。
    2. sendServiceArgsLocked() 調(diào)用其他生命周期方法,如onStartCommand()罢防。
    3. app.thread對象是 IApplicationThread 類型艘虎,實際上就是一個Binder,具體實現(xiàn)是ApplicationThread繼承ApplictionThreadNative咒吐。
  7. 具體看Application對Service的啟動過程app.thread.scheduleCreateService():通過sendMessage(H.CREATE_SERVICE , s) 野建,這個過程和Activity啟動過程類似,同時通過發(fā)送消息給Handler H來完成的恬叹。
  8. H會接受這個CREATE_SERVICE消息并通過ActivityThread的 handleCreateService() 來完成Service的最終啟動候生。
  9. handleCreateService()完成了以下工作:
    1. 通過ClassLoader創(chuàng)建Service對象。
    2. 創(chuàng)建Service內(nèi)部的Context對象绽昼。
    3. 創(chuàng)建Application唯鸭,并調(diào)用其onCreate()( 只會有一次)。
    4. 通過 service.attach() 方法建立Service與context的聯(lián)系( 與Activity類似)硅确。
    5. 調(diào)用service的 onCreate() 生命周期方法肿孵,至此,Service已經(jīng)啟動了疏魏。
    6. 將Service對象存儲到ActivityThread的一個ArrayMap中停做。
Service的綁定過程
Service的綁定過程

和service的啟動過程類似的:

  1. Service的綁定是從 ContextWrapper 的 bindService 開始。
  2. 在ContextWrapper中大莫,交給 ContextImpl 對象mBase.bindService()蛉腌。
  3. 最終會調(diào)用ContextImpl的 bindServiceCommon 方法,這個方法完成兩件事:
    1. 將客戶端的ServiceConnection轉(zhuǎn)化成 ServiceDispatcher.InnerConnection 對象只厘。ServiceDispatcher連接ServiceConnection和InnerConnection烙丛。這個過程通過 LoadedApk 的 getServiceDispatcher 方法來實現(xiàn),將客戶端的ServiceConnection和ServiceDispatcher的映射關(guān)系存在一個ArrayMap中羔味。
    2. 通過AMS來完成Service的具體綁定過程 ActivityManagerNative.getDefault().bindService()河咽。
  4. AMS中,bindService()方法再調(diào)用 bindServiceLocked() 赋元,bindServiceLocked()再調(diào)用 bringUpServiceLocked() 忘蟹,bringUpServiceLocked()又會調(diào)用 realStartServiceLocked() 飒房。
  5. AMS的realStartServiceLocked()會調(diào)用 ActiveServices 的requrestServiceBindingLocked() 方法,最終是調(diào)用了ServiceRecord對象r的 app.thread.scheduleBindService() 方法媚值。
  6. ApplicationThread的一系列以schedule開頭的方法狠毯,內(nèi)部都通過Handler H來中轉(zhuǎn):scheduleBindService()內(nèi)部也是通過 sendMessage(H.BIND_SERVICE , s)。
  7. 在H內(nèi)部接收到BIND_SERVICE這類消息時就交給 ActivityThread 的handleBindService() 方法處理:
    1. 根據(jù)Servcie的token取出Service對象褥芒。
    2. 調(diào)用Service的 onBind() 方法嚼松,至此,Service就處于綁定狀態(tài)了锰扶。
    3. 這時客戶端還不知道已經(jīng)成功連接Service献酗,需要調(diào)用客戶端的binder對象來調(diào)用客戶端的ServiceConnection中的 onServiceConnected() 方法,這個通過 ActivityManagerNative.getDefault().publishService() 進行坷牛。ActivityManagerNative.getDefault()就是AMS凌摄。
  8. AMS的publishService()交給ActivityService對象 mServices 的 publishServiceLocked() 來處理,核心代碼就一句話 c.conn.connected(r.name,service) 漓帅。對象c的類型是 ConnectionRecord 锨亏,c.conn就是ServiceDispatcher.InnerConnection對象,service就是Service的onBind方法返回的Binder對象忙干。
  9. 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)的。
  10. RunConnection的定義如下:
    1. 繼承Runnable接口施戴, run() 方法的實現(xiàn)也是簡單調(diào)用了ServiceDispatcher的 doConnected 方法反浓。
    2. 由于ServiceDispatcher內(nèi)部保存了客戶端的ServiceConntion對象,可以很方便地調(diào)用ServiceConntion對象的 onServiceConnected 方法赞哗。
    3. 客戶端的onServiceConnected方法執(zhí)行后雷则,Service的綁定過程也就完成了。
    4. 根據(jù)步驟8肪笋、9月劈、10service綁定后通過ServiceDispatcher通知客戶端的過程可以說明ServiceDispatcher起著連接ServiceConnection和InnerConnection的作用。 至于Service的停止和解除綁定的過程藤乙,系統(tǒng)流程都是類似的猜揪。

BroadcastReceiver的工作過程

簡單回顧一下廣播的使用方法, 首先定義廣播接收者, 只需要繼承BroadcastReceiver并重寫onReceive()方法即可. 定義好了廣播接收者, 還需要注冊廣播接收者, 分為兩種靜態(tài)注冊或者動態(tài)注冊. 注冊完成之后就可以發(fā)送廣播了。

廣播的注冊過程
廣播的注冊過程
  1. 動態(tài)注冊的過程是從ContextWrapper#registerReceiver()開始的. 和Activity或者Service一樣. ContextWrapper并沒有做實際的工作, 而是將注冊的過程直接交給了ContextImpl來完成坛梁。
  2. ContextImpl#registerReceiver()方法調(diào)用了本類的registerReceiverInternal()方法而姐。
  3. 系統(tǒng)首先從mPackageInfo獲取到IIntentReceiver對象, 然后再采用跨進程的方式向AMS發(fā)送廣播注冊的請求. 之所以采用IIntentReceiver而不是直接采用BroadcastReceiver, 這是因為上述注冊過程中是一個進程間通信的過程. 而BroadcastReceiver作為Android中的一個組件是不能直接跨進程傳遞的. 所有需要通過IIntentReceiver來中轉(zhuǎn)一下。
  4. IIntentReceiver作為一個Binder接口, 它的具體實現(xiàn)是LoadedApk.ReceiverDispatcher.InnerReceiver, ReceiverDispatcher的內(nèi)部同時保存了BroadcastReceiver和InnerReceiver, 這樣當(dāng)接收到廣播的時候, ReceiverDispatcher可以很方便的調(diào)用BroadcastReceiver#onReceive()方法. 這里和Service很像有同樣的類, 并且內(nèi)部類中同樣也是一個Binder接口划咐。
  5. 由于注冊廣播真正實現(xiàn)過程是在AMS中, 因此跟進AMS中, 首先看registerReceiver()方法, 這里只關(guān)心里面的核心部分. 這段代碼最終會把遠(yuǎn)程的InnerReceiver對象以及IntentFilter對象存儲起來, 這樣整個廣播的注冊就完成了拴念。
廣播的發(fā)送和接收過程
廣播的發(fā)送和接收過程

廣播的發(fā)送有幾種:普通廣播钧萍、有序廣播和粘性廣播,他們的發(fā)送/接收流程是類似的丈莺,因此只分析普通廣播的實現(xiàn)。

  1. 廣播的發(fā)送和接收, 本質(zhì)就是一個過程的兩個階段. 廣播的發(fā)送仍然開始于ContextImpl#sendBroadcase()方法, 之所以不是Context, 那是因為Context#sendBroad()是一個抽象方法. 和廣播的注冊過程一樣, ContextWrapper#sendBroadcast()仍然什么都不做, 只是把事情交給了ContextImpl去處理送丰。
  2. ContextImpl里面也幾乎什么都沒有做, 內(nèi)部直接向AMS發(fā)起了一個異步請求用于發(fā)送廣播缔俄。
  3. 調(diào)用AMS#broadcastIntent()方法,繼續(xù)調(diào)用broadcastIntentLocked()方法器躏。
  4. 在broadcastIntentLocked()內(nèi)部, 會根據(jù)intent-filter查找出匹配的廣播接收者并經(jīng)過一系列的條件過濾. 最終會將滿足條件的廣播接收者添加到BroadcastQueue中, 接著BroadcastQueue就會將廣播發(fā)送給相應(yīng)廣播接收者俐载。
  5. BroadcastQueue#scheduleBroadcastsLocked()方法內(nèi)并沒有立即發(fā)送廣播, 而是發(fā)送了一個BROADCAST_INTENT_MSG類型的消息, BroadcastQueue收到消息后會調(diào)用processNextBroadcast()方法。
  6. 無序廣播存儲在mParallelBroadcasts中, 系統(tǒng)會遍歷這個集合并將其中的廣播發(fā)送給他們所有的接收者, 具體的發(fā)送過程是通過deliverToRegisteredReceiverLocked()方法實現(xiàn)登失。deliverToRegisteredReceiverLocked()負(fù)責(zé)將一個廣播發(fā)送給一個特定的接收者, 它的內(nèi)部調(diào)用了performReceiverLocked方法來完成具體發(fā)送過程遏佣。
  7. performReceiverLocked()方法調(diào)用的ApplicationThread#scheduleRegisteredReceiver()實現(xiàn)比較簡單, 它通過InnerReceiver來實現(xiàn)廣播的接收。
  8. scheduleRegisteredReceiver()方法中揽浙,receiver.performReceive()中的receiver對應(yīng)著IIntentReceiver類型的接口. 而具體的實現(xiàn)就是ReceiverDispatcher$InnerReceiver. 這兩個嵌套的內(nèi)部類是所屬在LoadedApk中的状婶。
  9. 又調(diào)用了LoadedApk$ReceiverDispatcher#performReceive()的方法.在performReceiver()這個方法中, 會創(chuàng)建一個Args對象并通過mActivityThread的post方法執(zhí)行args中的邏輯. 而這些類的本質(zhì)關(guān)系就是:
    1. Args: 實現(xiàn)類Runnable。
    2. mActivityThread: 是一個Handler, 就是ActivityThread中的mH. mH就是ActivityThread$H. 這個內(nèi)部類H以前說過馅巷。
  10. 實現(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)象局齿。

ContentProvider的工作機制
  1. 當(dāng)一個應(yīng)用啟動時,入口方法是ActivityThread的main方法橄登,其中創(chuàng)建ActivityThread的實例并創(chuàng)建主線程的消息隊列项炼。
  2. ActivityThread的attach方法中會遠(yuǎn)程調(diào)用ActivityManagerService的attachApplication,并將ApplicationThread提供給AMS示绊,ApplicationThread主要用于ActivityThread和AMS之間的通信锭部。
  3. ActivityManagerService的attachApplication會調(diào)用ApplicationThread的bindApplication方法,這個方法會通過H切換到ActivityThread中去執(zhí)行面褐,即調(diào)用handleBindApplication方法拌禾。
  4. handleBindApplication方法會創(chuàng)建Application對象并加載ContentProvider,注意是先加載ContentProvider展哭,然后調(diào)用Application的onCreate方法湃窍。
  5. 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)用為例:


  1. 首先會獲取IContentProvider對象, 不管是通過acquireUnstableProvider()方法還是直接通過acquireProvider()方法, 他們的本質(zhì)都是一樣的, 最終都是通過acquireProvider方法來獲取ContentProvider。
  2. ApplicationContentResolver#acquireProvider()方法并沒有處理任何邏輯, 它直接調(diào)用了ActivityThread#acquireProvider()唠雕。
  3. 從ActivityThread中查找是否已經(jīng)存在了ContentProvider了, 如果存在那么就直接返回. ActivityThread中通過mProviderMap來存儲已經(jīng)啟動的ContentProvider對象, 這個集合的存儲類型ArrayMap mProviderMap. 如果目前ContentProvider沒有啟動, 那么就發(fā)送一個進程間請求給AMS讓其啟動項目目標(biāo)ContentProvider, 最后再通過installProvider()方法來修改引用計數(shù)贸营。
  4. AMS是如何啟動ContentProvider的呢?首先會啟動ContentProvider所在的進程, 然后再啟動ContentProvider. 啟動進程是由AMS#startProcessLocked()方法來完成, 其內(nèi)部主要是通過Process#start()方法來完成一個新進程的啟動, 新進程啟動后其入口方法為ActivityThread#main()方法。
  5. ActivityThread#main()是一個靜態(tài)方法, 在它的內(nèi)部首先會創(chuàng)建ActivityThread實例并調(diào)用attach()方法來進行一系列初始化, 接著就開始進行消息循環(huán). ActivityThread#attach()方法會將Application對象通過AMS#attachApplication方法跨進程傳遞給AMS, 最終AMS會完成ContentProvider的創(chuàng)建過程岩睁。
  6. AMS#attachApplication()方法調(diào)用了attachApplication(), 然后又調(diào)用了ApplicationThread#bindApplication(), 這個過程也屬于進程通信.bindApplication()方法會發(fā)送一個BIND_APPLICATION類型的消息給mH, 這是一個Handler, 它收到消息后會調(diào)用ActivityThread#handleBindApplication()方法莽使。
  7. ActivityThread#handlerBindApplication()則完成了Application的創(chuàng)建以及ContentProvider 可以分為如下四個步驟:
    1. 創(chuàng)建ContentProvider和Instrumentation。
    2. 創(chuàng)建Application對象笙僚。
    3. 啟動當(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()芳肌。
    4. 調(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()方法。

更多內(nèi)容戳這里(整理好的各種文集)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末栋猖,一起剝皮案震驚了整個濱河市净薛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蒲拉,老刑警劉巖肃拜,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異雌团,居然都是意外死亡燃领,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門锦援,熙熙樓的掌柜王于貴愁眉苦臉地迎上來猛蔽,“玉大人,你說我怎么就攤上這事÷猓” “怎么了区岗?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長毁枯。 經(jīng)常有香客問我慈缔,道長,這世上最難降的妖魔是什么种玛? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任藐鹤,我火速辦了婚禮,結(jié)果婚禮上蒂誉,老公的妹妹穿的比我還像新娘教藻。我一直安慰自己距帅,他們只是感情好右锨,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著碌秸,像睡著了一般绍移。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上讥电,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天蹂窖,我揣著相機與錄音,去河邊找鬼恩敌。 笑死瞬测,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的纠炮。 我是一名探鬼主播月趟,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼恢口!你這毒婦竟也來了孝宗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤耕肩,失蹤者是張志新(化名)和其女友劉穎因妇,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體猿诸,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡婚被,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了梳虽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摔寨。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖怖辆,靈堂內(nèi)的尸體忽然破棺而出是复,到底是詐尸還是另有隱情删顶,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布淑廊,位于F島的核電站逗余,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏季惩。R本人自食惡果不足惜录粱,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望画拾。 院中可真熱鬧啥繁,春花似錦、人聲如沸青抛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赦肃。三九已至勿负,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間举瑰,已是汗流浹背捣辆。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留此迅,地道東北人汽畴。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像耸序,于是被迫代替她去往敵國和親忍些。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

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