Android四大組件的工作過(guò)程晕窑,原理解析

一、Activity啟動(dòng)過(guò)程

? ? 首先我們要知道Activity有冷啟動(dòng)和熱啟動(dòng)之分卵佛,通俗來(lái)說(shuō)冷啟動(dòng)就是應(yīng)用進(jìn)程尚未創(chuàng)建杨赤,熱啟動(dòng)則已經(jīng)創(chuàng)建完成。

? ??在點(diǎn)擊桌面應(yīng)用圖標(biāo)時(shí)截汪,即將要啟動(dòng)的App將和Launcher疾牲、AMS、Zygote這三者多次通信挫鸽,才會(huì)啟動(dòng)一個(gè)App,然后再啟動(dòng)Activity说敏。

追蹤源碼,我們可以得到以下整體的時(shí)序圖:

Activity啟動(dòng)時(shí)序圖

簡(jiǎn)單的梳理下整體流程丢郊,我們可以直接得到以下流程:

Activity啟動(dòng)總體流程圖

Launcher進(jìn)程通過(guò)Binder機(jī)制通知AMS

AMS則判斷應(yīng)用進(jìn)程是否已經(jīng)存在(冷啟動(dòng))盔沫,不存在則通過(guò)Socket通訊通知Zygote進(jìn)程fork應(yīng)用進(jìn)程,已經(jīng)啟動(dòng)(熱啟動(dòng))則無(wú)需再次創(chuàng)建App進(jìn)程枫匾。

應(yīng)用進(jìn)程創(chuàng)建完成之后則會(huì)通過(guò)Binder機(jī)制通知AMS 創(chuàng)建完成架诞。

AMS通過(guò)Binder機(jī)制請(qǐng)求ApplicationThread創(chuàng)建并啟動(dòng)根Activity。

ApplicationThread通過(guò)Handle機(jī)制通知主線程ActivityThread干茉,最終調(diào)用到根Activity的onCreate谴忧、onStart、onResume等方法完成創(chuàng)建角虫。

二沾谓、Service的啟動(dòng)過(guò)程

????Service的啟動(dòng)還是和Activity有很多相似處的,都需要和AMS打招呼戳鹅。

????眾所周知均驶,Service的啟動(dòng)有兩種方式一種StartService,一種bindService枫虏,那它們的啟動(dòng)過(guò)程是否一樣呢妇穴?帶著疑惑我們往下看。

????首先我們看StartService隶债,直接分析源碼腾它,可以得到以下時(shí)序圖:

startService時(shí)序圖1
startService時(shí)序圖2

????注:1.bringUpServiceLocked方法調(diào)用時(shí),其中啟動(dòng)Service時(shí)會(huì)判斷app==null死讹,app的類型是ProcessRecord瞒滴,用來(lái)描述運(yùn)行的應(yīng)用程序進(jìn)程的信息,在其中將Service運(yùn)行的進(jìn)程名和uid傳遞給ActivityManagerService的getProcessRecordLocked方法赞警,從而獲取運(yùn)行Service的應(yīng)用程序進(jìn)程信息ProcessRecord妓忍,如果用來(lái)運(yùn)行Service的應(yīng)用程序進(jìn)程不存在稀并,就會(huì)調(diào)用ActivityManagerService的startProcessLocked方法來(lái)創(chuàng)建對(duì)應(yīng)的應(yīng)用程序進(jìn)程;如果用來(lái)運(yùn)行Service的應(yīng)用程序進(jìn)程存在单默,會(huì)調(diào)用realStartServiceLocked方法。

????2.H是ActivityThread的內(nèi)部類并繼承自Handler忘瓦,AMS通過(guò)IApplicationThread向應(yīng)用程序進(jìn)程發(fā)送消息搁廓,接受消息的操作是在應(yīng)用程序進(jìn)程的Binder線程池中進(jìn)行,因此需要Handler來(lái)發(fā)送消息切換到主線程耕皮。

????總結(jié)下來(lái)就是

startService總流程

????下面接著分析下bindService境蜕,它的流程會(huì)相對(duì)startService復(fù)雜一丟丟,照例直接分析源碼凌停,可以得到以下時(shí)序圖:

bindService時(shí)序圖1
bindService時(shí)序圖2

????大致總結(jié)一下就是應(yīng)用進(jìn)程這邊調(diào)用一系列方法最終與AMS通信bindService粱年,然后AMS中調(diào)用activeService類中的方法,然后又通過(guò)ApplicationThread與應(yīng)用進(jìn)程這邊通信handleBindService罚拟,然后通知AMS去publishService台诗,調(diào)用的activeService的publishServiceLocked方法,其中調(diào)用了ServiceDispatcher.InnerConnection的connected方法赐俗,再調(diào)用ServiceDispatcher的connected方法拉队,ServiceDispatcher是LoadedApk的內(nèi)部類,并調(diào)用Handler類型的對(duì)象mActivityThread的post方法阻逮,mActivityThread實(shí)際指向的是ActivityThread的內(nèi)部類H粱快,最終通過(guò)H類的post方法將RunConnection對(duì)象的內(nèi)容運(yùn)行在主線程中,RunConnections是LoadedApk的內(nèi)部類叔扼,最后調(diào)用mConnection的onServiceConnected事哭,mConnection的類型是ServiceConnection,這樣客戶端實(shí)現(xiàn)ServiceConnection接口類的onServiceConnected方法就會(huì)被調(diào)用瓜富。

三鳍咱、BroadcastReceiver的注冊(cè)、發(fā)送和接收

? ?廣播注冊(cè)分為動(dòng)態(tài)注冊(cè)和靜態(tài)注冊(cè)食呻,首先我們分析動(dòng)態(tài)注冊(cè)流炕。

????動(dòng)態(tài)注冊(cè)的過(guò)程是從ContextWrapper#registerReceiver()開(kāi)始的. 和Activity或者Service一樣. ContextWrapper并沒(méi)有做實(shí)際的工作, 而是將注冊(cè)的過(guò)程直接交給了ContextImpl來(lái)完成。

????ContextImpl#registerReceiver()方法調(diào)用了本類的registerReceiverInternal()方法仅胞。

????系統(tǒng)首先從mPackageInfo獲取到IIntentReceiver對(duì)象, 然后再采用跨進(jìn)程的方式向AMS發(fā)送廣播注冊(cè)的請(qǐng)求. 之所以采用IIntentReceiver而不是直接采用BroadcastReceiver, 這是因?yàn)樯鲜鲎?cè)過(guò)程中是一個(gè)進(jìn)程間通信的過(guò)程. 而BroadcastReceiver作為Android中的一個(gè)組件是不能直接跨進(jìn)程傳遞的. 所以需要通過(guò)IIntentReceiver來(lái)實(shí)現(xiàn)通信每辟。

????IIntentReceiver作為一個(gè)Binder接口, 它的具體實(shí)現(xiàn)是LoadedApk.ReceiverDispatcher.InnerReceiver, ReceiverDispatcher的內(nèi)部同時(shí)保存了BroadcastReceiver和InnerReceiver, 這樣當(dāng)接收到廣播的時(shí)候, ReceiverDispatcher可以很方便的調(diào)用BroadcastReceiver#onReceive()方法. 這里和Service很像有同樣的類, 并且內(nèi)部類中同樣也是一個(gè)Binder接口。

????由于注冊(cè)廣播真正實(shí)現(xiàn)過(guò)程是在AMS中, 因此跟進(jìn)AMS中, 首先看registerReceiver()方法, 這里只關(guān)心里面的核心部分. 這段代碼最終會(huì)把遠(yuǎn)程的InnerReceiver對(duì)象以及IntentFilter對(duì)象存儲(chǔ)起來(lái), 這樣整個(gè)廣播的注冊(cè)就完成了干旧。

靜態(tài)注冊(cè)的過(guò)程就比較簡(jiǎn)單

1.AndroidManifest.xml中的receiver解析成ParsedActivity, 存放在PackageImpl的receivers(PackageImpl父類是ParsingPackageImpl而且實(shí)現(xiàn)了AndroidPackage接口)

2.receivers最終會(huì)存放在mComponentResolver(PMS)的mReceivers中渠欺,mReceivers包含了所有安裝應(yīng)用的receiver,通過(guò)ComponentName就可以獲得相應(yīng)的ParsedActivity椎眯,如:

3.mReceivers.mActivities.get(new ComponentName(“com.example.myapplication”, “com.example.myapplication.MyReceive”))挠将,既可以獲得MyReceiver的ParsedActivity

4.receiver中的一個(gè)IntentFilter(intent-filter)對(duì)應(yīng)一個(gè)ParsedIntentInfo胳岂,一個(gè)Pair<ParsedActivity, ParsedIntentInfo>

5.Pair<ParsedActivity, ParsedIntentInfo>被放入mComponentResolver的mFilters

6.mActions被放入mComponentResolver的mActionToFilter

????部分靜態(tài)廣播注冊(cè)需要權(quán)限,不是注冊(cè)了就能收到舔稀。其實(shí)要接收廣播還:涉及權(quán)限乳丰、進(jìn)程優(yōu)先級(jí)、flag標(biāo)簽等各類無(wú)法接收到廣播的情況内贮〔埃總而言之靜態(tài)廣播注冊(cè)是在包安裝解析的時(shí)候就開(kāi)始注冊(cè),并將廣播信息存儲(chǔ)在PMS(PackageManagerService)中了夜郁。

? ??廣播的發(fā)送主要有幾種:普通廣播什燕、有序廣播。

? ? 前面都一樣都是通過(guò)ContextImpl去與AMS打交道竞端,然后AMS這邊方法中會(huì)根據(jù)intent-filter查找出匹配的廣播接收者并經(jīng)過(guò)一系列的條件過(guò)濾. 最終會(huì)將滿足條件的廣播接收者添加到BroadcastQueue中, 接著BroadcastQueue就會(huì)將廣播發(fā)送給相應(yīng)廣播接收者屎即。應(yīng)用接收到廣播, 同時(shí)onReceive()方法是在廣播接收者的主線程中被調(diào)用的。

普通廣播發(fā)送

補(bǔ)充小知識(shí)

1:所有靜態(tài)廣播Receiver 都是串行處理事富,(靜態(tài)廣播接收者屬于在發(fā)送此廣播時(shí)屬于有序廣播范疇)

2:動(dòng)態(tài)廣播 Receiver按照發(fā)送此廣播時(shí)指定的方式 進(jìn)行 串行或者并行分發(fā)

其中:如果是普通廣播:那么通過(guò) 并行方式分發(fā)

? ? ? ? 如果是 有序廣播(sendOrderxxxx):那么通過(guò) 串行方式分發(fā)

3:Android系統(tǒng)在處理廣播時(shí):動(dòng)態(tài)廣播接收者 優(yōu)先于 靜態(tài)廣播接收者 收到

4:廣播分發(fā)處理關(guān)鍵類:BroadcastQueue/ BroadcastRecord

5.本地廣播:為了解決全局廣播的安全性問(wèn)題技俐,Android引進(jìn)了本地廣播機(jī)制。本地廣播發(fā)出后只能夠在應(yīng)用程序內(nèi)部傳遞统台,也只有應(yīng)用程序內(nèi)部的接收器能接收到本地廣播虽另,這樣廣播的安全性問(wèn)題就能得到解決了。本地廣播和全局廣播不同的地方在于本地廣播主要使用LocalBroadcastManager對(duì)廣播的發(fā)送饺谬、注冊(cè)捂刺、注銷進(jìn)行管理。

四募寨、ContentProvider的啟動(dòng)過(guò)程

????ContentProvider的啟動(dòng)過(guò)程和其他3大組件基本類似族展,都是通過(guò)AMS實(shí)現(xiàn)進(jìn)程間的數(shù)據(jù)共享。

????在activity中如果想通過(guò)provider來(lái)實(shí)現(xiàn)增刪查改拔鹰,首先需要獲取contentprovider仪缸,大致過(guò)程為在context中獲取contentResolver,然后通過(guò)contentResolver去ActivityManagerService中查詢對(duì)應(yīng)的provider列肢,如果沒(méi)有則進(jìn)入PackageManagerService中查找:

????1)首先每個(gè)context類都會(huì)內(nèi)部包含了一個(gè)ContentResolver的子對(duì)象ApplicationContentResolver恰画。

????2)通過(guò)調(diào)用ApplicationContentResolver的主要方法query來(lái)獲取CP的數(shù)據(jù)庫(kù)數(shù)據(jù)。

????3)調(diào)用的過(guò)程首先會(huì)調(diào)用ContentResolver的核心方法acquireProvider()瓷马。而acquireProvider()方法是一個(gè)抽象方法拴还,其實(shí)現(xiàn)是交由子類實(shí)現(xiàn)。

????4)通過(guò)子類的acquireProvider()方法實(shí)現(xiàn)了解到主要的實(shí)現(xiàn)是交由ActivityThread類來(lái)完成欧聘。

????5)ActivityThread類會(huì)做出一個(gè)判斷片林,如果本地保存一個(gè)需要獲取的CP對(duì)象實(shí)例,就會(huì)直接返回這個(gè)對(duì)象實(shí)例,如果沒(méi)有保存费封,則會(huì)訪問(wèn)AMS對(duì)象去查找獲取一個(gè)對(duì)象的CP對(duì)象實(shí)例焕妙,當(dāng)找到這個(gè)對(duì)象實(shí)例后會(huì)保存到本地以便日后快速獲取。

????6)如果在AMS里面沒(méi)有找到弓摘,就會(huì)繼續(xù)深入到PMS里去從全部的provider中查找焚鹊。

????7)獲取到CP對(duì)象實(shí)例后會(huì)通過(guò)層層返回,最后再調(diào)用該CP對(duì)象的query方法獲取相應(yīng)的數(shù)據(jù)韧献。

首先在應(yīng)用的的manifest中需要進(jìn)行讀寫權(quán)限申明,這個(gè)申明的定義跟之前provider定義中讀寫所需權(quán)限屬性值是一樣的:

????在activity中獲取ContentResolver調(diào)用其中的操作方法時(shí)寺旺,需要傳入相對(duì)應(yīng)的參數(shù):

????contentResolver.query(Uri uri, String[] projection,String selection, String[] selectionArgs,String orderBy);

????uri:傳入對(duì)應(yīng)uri是為了查找到對(duì)應(yīng)的provider,跟provider在manifest中定義的authorities值是一樣

????projection:選擇需要返回的對(duì)象屬性值势决,有時(shí)候不需要將對(duì)象的值全部返回。

????selection/selectionArgs:查詢條件

????orderBy: 返回的對(duì)象排序方式

????類似其他的delete蓝撇、insert和update操作果复。最主要的是傳入正確的Uri才能找到對(duì)應(yīng)的provider。

????此處加個(gè)小知識(shí)點(diǎn):ContentProvider onCreate()優(yōu)先執(zhí)行于 Application onCreate()方法渤昌,感興趣的小伙伴可以通過(guò)查看源碼的方式驗(yàn)證虽抄。

淺談一個(gè)小知識(shí)點(diǎn)—AMS的啟動(dòng):

????AMS,即ActivityManagerService独柑,是安卓java framework的一個(gè)服務(wù)迈窟,運(yùn)行在system_server進(jìn)程。

????在系統(tǒng)開(kāi)機(jī)啟動(dòng)之后忌栅,system_server會(huì)執(zhí)行三大服務(wù)啟動(dòng)

????startBootstrapServices() :?jiǎn)?dòng)引導(dǎo)服務(wù)车酣,在這里實(shí)際上已經(jīng)new了AMS,在new方法里索绪,已經(jīng)初始化了AMS的大部分重要的屬性。AMS的Looper和各種handler也是在這里準(zhǔn)備好的瑞驱。

????startCoreServices():核心服務(wù)娘摔。

????在創(chuàng)建完AMS之后凳寺,system_server的run方法會(huì)執(zhí)行到startOtherServices(),在啟動(dòng)“其他服務(wù)”完畢之后杆融,會(huì)調(diào)入到AMS的systemReady()方法,在這里會(huì)啟動(dòng)launcher激况。

????可以說(shuō)灿渴,在這個(gè)方法執(zhí)行完畢之后够话,系統(tǒng)就已經(jīng)啟動(dòng)完成了蓝翰。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市女嘲,隨后出現(xiàn)的幾起案子畜份,更是在濱河造成了極大的恐慌,老刑警劉巖欣尼,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爆雹,死亡現(xiàn)場(chǎng)離奇詭異停蕉,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)钙态,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門慧起,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人册倒,你說(shuō)我怎么就攤上這事蚓挤。” “怎么了驻子?”我有些...
    開(kāi)封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵灿意,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我崇呵,道長(zhǎng)缤剧,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任域慷,我火速辦了婚禮荒辕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芒粹。我一直安慰自己,他們只是感情好大溜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布化漆。 她就那樣靜靜地躺著,像睡著了一般钦奋。 火紅的嫁衣襯著肌膚如雪座云。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天付材,我揣著相機(jī)與錄音朦拖,去河邊找鬼。 笑死厌衔,一個(gè)胖子當(dāng)著我的面吹牛璧帝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播富寿,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼睬隶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了页徐?” 一聲冷哼從身側(cè)響起苏潜,我...
    開(kāi)封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎变勇,沒(méi)想到半個(gè)月后恤左,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年飞袋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了戳气。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡授嘀,死狀恐怖物咳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蹄皱,我是刑警寧澤览闰,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站巷折,受9級(jí)特大地震影響压鉴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜锻拘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一油吭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧署拟,春花似錦婉宰、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至馒铃,卻和暖如春蟹腾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背区宇。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工娃殖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人议谷。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓炉爆,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親卧晓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子叶洞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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