Application和四大組件啟動(dòng)時(shí)的方法順序和相關(guān)注意事項(xiàng)

作者簡(jiǎn)介? 創(chuàng)微信公眾號(hào)郭霖 WeChat ID: guolin_blog

本篇來自WizardDragon的投稿凉倚,分享了他對(duì)于四大組件啟動(dòng)時(shí)一些方法的調(diào)用順序的研究結(jié)果,并且深入源碼去分析遇到的問題。文章篇幅不短掺冠,希望能對(duì)大家有所幫助来颤。

WizardDragon的博客地址:

http://blog.csdn.net/long117long

背景

在做一個(gè)項(xiàng)目時(shí),我們想在應(yīng)用最早啟動(dòng)時(shí)囤躁,先做一些判斷冀痕,然后根據(jù)判斷的結(jié)果再?zèng)Q定要不要對(duì)其他應(yīng)用提供服務(wù)荔睹。

對(duì)其他應(yīng)用提供服務(wù)指的是,我們的應(yīng)用中有 ContentProvider言蛇,第三方應(yīng)用通過 call 方法調(diào)用到我們提供的 ContentProvider僻他,ContentProvider 執(zhí)行邏輯后并給調(diào)用的返回結(jié)果。當(dāng)?shù)谌綉?yīng)用調(diào)用我們的應(yīng)用時(shí)腊尚,我們的應(yīng)用存在啟動(dòng)和未啟動(dòng)的兩種情況吨拗。

剛開始,我們將判斷邏輯寫在了自定義的 Application 的 onCreate 方法中婿斥,但等到測(cè)試時(shí)發(fā)現(xiàn)了很多意想不到的情況劝篷,比如:

邏輯判斷之后的結(jié)果是不給第三方應(yīng)用提供“服務(wù)”,但有時(shí)候第三方應(yīng)用能夠使用服務(wù)民宿,而有時(shí)候第三方應(yīng)用不能使等等的問題娇妓。

于是我們跟蹤代碼,發(fā)現(xiàn)了?四大組件 以及 Application 的各個(gè)方法( attachBaseContext活鹰、onCreate哈恰、call 等)啟動(dòng)順序,跟我們之前理解的稍稍不一樣志群。

在弄清楚了 四大組件 和 Application?在應(yīng)用冷啟動(dòng)時(shí)的執(zhí)行順序后着绷,我們才把遇到的問題徹底解決。

驗(yàn)證試驗(yàn)

為了測(cè)試?四大組件 和 Application 的各種方法( attachBaseContext锌云、onCreate荠医、call 等)被系統(tǒng)調(diào)用的順序,我們創(chuàng)建一個(gè)簡(jiǎn)單的應(yīng)用宾抓,只包含這5個(gè)組件子漩,不考慮一個(gè)應(yīng)用多進(jìn)程的情況,代碼分別為:


MainApplication.java


MainActivity.java


MainService.java


MainReceiver.java


MainProvider.java


在以下幾個(gè)場(chǎng)景測(cè)試時(shí)石洗,均已冷啟動(dòng)的方式啟動(dòng)應(yīng)用幢泼。

冷啟動(dòng),指的是在系統(tǒng)沒有創(chuàng)建apk這個(gè)進(jìn)程時(shí)啟動(dòng)apk讲衫。

注意在測(cè)試的手機(jī)上缕棵,不要讓測(cè)試的應(yīng)用被禁止關(guān)聯(lián)啟動(dòng)或自啟動(dòng):

場(chǎng)景一,點(diǎn)擊桌面的圖標(biāo)啟動(dòng)應(yīng)用涉兽,日志如下:


場(chǎng)景二招驴,通過另外一個(gè)應(yīng)用以啟動(dòng)Service的形式啟動(dòng)應(yīng)用,其中啟動(dòng) MainService 的代碼如下:


日志如下:


場(chǎng)景三枷畏,應(yīng)用通過接受開機(jī)廣播啟動(dòng)的方式啟動(dòng)别厘,日志如下:


場(chǎng)景四,其他應(yīng)用調(diào)用 ContentProvider 的 call 方法啟動(dòng)拥诡,其中触趴,調(diào)用 MainProvider 的 call 代碼如下:


日志如下:


結(jié)論:

從上面四個(gè)場(chǎng)景可以看出:

1.Application 的 attachBaseContext 方法是優(yōu)先執(zhí)行的氮发;

2.ContentProvider 的 onCreate 的方法比 Application 的 onCreate 的方法先執(zhí)行;

3.Activity冗懦、Service的 onCreate 方法以及 BroadcastReceiver 的 onReceive 方法爽冕,是在 MainApplication 的 onCreate 方法之后執(zhí)行的;

4.調(diào)用流程為: Application 的 attachBaseContext ---> ContentProvider 的 onCreate ----> Application 的 onCreate ---> Activity披蕉、Service 等的 onCreate(Activity 和 Service 不分先后)颈畸;

問題

問題一:ContentProvider 的 onCreate 一定是優(yōu)先于 Application 的 onCreate 執(zhí)行的嗎?

為了驗(yàn)證這個(gè)問題没讲,MainApplication 的代碼不變眯娱,我們將 MainProvider 的 onCreate 的代碼改為:


我們?cè)僭谏厦娴谒姆N場(chǎng)景上進(jìn)行驗(yàn)證,日志如下:


問題一結(jié)論:

確實(shí)是在 ContentProvider 的 onCreate 執(zhí)行完成之后食零,才會(huì)執(zhí)行 Application 的 onCreate 的困乒。

問題二:ContentProvider中 的 call方法 是在 Application 的 onCreate 執(zhí)行完之后才執(zhí)行的嗎寂屏?

為了驗(yàn)證這個(gè)問題贰谣,我們將 MainProvider 和 MainApplication 的代碼改為:



我們還在第四個(gè)場(chǎng)景下驗(yàn)證,日志如下:


從日志中可以發(fā)現(xiàn)迁霎,Application 的 onCreate 執(zhí)行時(shí)吱抚,ContentProvider 的 call方法 也在同時(shí)執(zhí)行。

問題二結(jié)論:

Application 的 onCreate方法 和 Provider 的 call方法不是順序執(zhí)行考廉,而是會(huì)同時(shí)執(zhí)行秘豹。

問題三:有比 Application 的 attachBaseContext方法 更早執(zhí)行的方法嗎?

有昌粤,比如:Application所在類的構(gòu)造方法既绕。為了驗(yàn)證這個(gè)問題,將代碼改為:


程序啟動(dòng)后涮坐,日志為:


問題三結(jié)論:

Application 的構(gòu)造方法早于?Application 的 attachBaseContext方法 調(diào)用凄贩。

那么有沒有比 Application 的構(gòu)造方法還早被調(diào)用的方法呢?有袱讹,自己可以再想想哦疲扎。

遇到的坑

好了,我們知道 attachBaseContext 的方法在“一般情況下是最早執(zhí)行的“捷雕,那么在項(xiàng)目中為了能”盡早“的提前初始化某些模塊椒丧、功能或者參數(shù),那么我們會(huì)把代碼從 Application 的onCreate方法 提前到 attachBaseContext方法 中救巷。嗯壶熏,一切感覺起來那么美好,直到你運(yùn)行程序崩潰時(shí)...

好吧好吧浦译,那些“坑”終于還是來了棒假。

“坑”一:在 Application 的 attachBaseContext方法 中俄占,使用了 getApplicationContext方法。

當(dāng)我發(fā)現(xiàn)在 attachBaseContext方法 中使用 getApplicationContext方法 返回null時(shí)淆衷,內(nèi)心是崩潰缸榄。

所以,如果在 attachBaseContext方法 中要使用 context 的話祝拯,那么使用this吧甚带,別再使用 getApplicationContext() 方法了。下文有分析為什么佳头。

“坑”二:這個(gè)其實(shí)不算很坑鹰贵,也不會(huì)引起崩潰,但需要注意:

在 Application 的 attachBaseContext方法 中康嘉,去調(diào)用自身的?ContentProvider碉输,那么這個(gè)?ContentProvider?會(huì)被初始化兩次,也就是說這個(gè) ContentProvider 會(huì)被兩次調(diào)用到onCreate亭珍。如果你在 ContentProvider 的 onCreate 中有一些邏輯敷钾,那么一定要檢查是否會(huì)有影響。

做一下驗(yàn)證肄梨,在 Application 中調(diào)用 Provider 的 call方法阻荒,并在 MainActivity 中的 onCreate方法 中調(diào)用 Provider 的 call方法,Application 的代碼众羡,Provider 的代碼侨赡,Activity 的代碼分別如下:


啟動(dòng)應(yīng)用后,日志如下:


可以看到粱侣,MainProvider 的 onCreate 的方法被調(diào)用了兩次(因?yàn)?MainProvider 的兩次 onCreate 打印出的自身對(duì)象不一樣)羊壹,而在 MainActivity 中調(diào)用到 call方法 執(zhí)行的類,跟 MainApplication 在 attachBaseContext方法 執(zhí)行的類是同一個(gè)齐婴。

源碼分析

好了油猫,現(xiàn)象、問題和“坑”都經(jīng)歷了一遍尔店,那么 為什么 會(huì)是這樣呢眨攘?

我們通過看源碼,來跟蹤:

1.Application 的 attachBaseContext嚣州、ContentProvider 的 onCreate 以及 Application 的 onCreate 在源碼中的調(diào)用順序鲫售。

2.為什么在 Application 的 attachBaseContext 中調(diào)用 getApplicationContext 得到的是null

先看第一個(gè)問題该肴,我們知道Java進(jìn)程的入口方法一般都是在main中情竹,而Android為了讓應(yīng)用開發(fā)者不需要關(guān)心應(yīng)用的創(chuàng)建,已經(jīng)幫我們進(jìn)行封裝匀哄,其實(shí)應(yīng)用 main方法 是在 ActivityThread.java?中的秦效。

我們查看 ActivityThread.java 的源碼雏蛮,本文以下的源碼都以6.0.1_r10基礎(chǔ)。

a. ActivityThread.java 的 main方法:


b. ActivityThread.java 的 attach方法:


c. ActivityThread.java 的 handleBindApplication(AppBindData data)方法:


d. LoaderApk.java 的 makeApplication方法


e. Instrumentation.java的相關(guān)方法


f. Application.java 的 attach方法


g.?ActivityThread.java 的 handleBindApplication方法:


h. 繼續(xù)跟蹤 installContentProviders 這個(gè)方法阱州,而這個(gè)方法是會(huì)調(diào)用到 installProvider方法 中的挑秉,還是在 ActivityThread.java 中:


i. 看 ContentProvider.java 中的 attachInfo方法(frameworks/base/core/java/android/content/ContentProvider.java)


j. 關(guān)于 注釋7 的 mInstrumentation.callApplicationOnCreate(app) 調(diào)用到的?Instrumentation.java 中的方法


看第二問題,為什么在我們自定義 Application 中的 attachBaseContext方法 中苔货,調(diào)用 getApplicationContext() 為 null 呢犀概?

1. 跟蹤 getApplicationContext() 發(fā)現(xiàn)是在 ContextWrapper.java 中實(shí)現(xiàn)的:


2. 我們看 ContextImpl 的 getApplicationContext方法:


3. mPackageInfo 是什么時(shí)候賦值的呢?我們從 ContextImpl 實(shí)例化的地方入手夜惭,在注釋 5.1 之前的一行代碼看到了?ContextImpl 的實(shí)例化代碼姻灶,跟進(jìn)代碼發(fā)現(xiàn),果不其然诈茧,看到了 mPackageInfo 被賦值的地方:


4. 注釋b.1所在的流程 ?早于 注釋5.4 的(在注釋5.4時(shí)才調(diào)用到了Application的attachBaseContext方法)产喉,在我們自定義的Application中attachBaseContext調(diào)用getApplicationContext方法時(shí),就到了注釋b敢会,而此時(shí)mPackageInfo是不為空的曾沈,所以會(huì)執(zhí)行mPackageInfo.getApplication(),那么我們?cè)倏匆幌翷oadedApk.java中的getApplication方法(正如前面所說走触,mPackageInfo是LoadedApk的實(shí)例)晦譬,



看到這里找到原因所在了:

因?yàn)槲覀冊(cè)?Application 的 attachBaseContext方法 中調(diào)用 getApplicationContext() 時(shí), mApplication 還沒有被賦值互广,所以返回的是空,只有把 attachBaseContext方法 執(zhí)行完成后卧土,mApplication 才會(huì)被賦值惫皱。

附圖一張:


參考

http://androidxref.com

http://blog.csdn.net/u011228356/article/details/45102623

http://www.wtoutiao.com/p/1f8OfGz.html

文章原創(chuàng)作者GuoLin 書籍推薦

郭林大神原創(chuàng)android 書籍:《第一行代碼 android》

淘寶鏈接: https://s.click.taobao.com/t?e=m%3D2%26s%3DgKUfuKdAZKocQipKwQzePOeEDrYVVa64K7Vc7tFgwiHjf2vlNIV67p2n%2BQBNMyE6Rku8%2Bpj6eJall3bs%2B3NRhNHnsKI%2BqxhyM0iVZhTFBom4YIorMPnmg8G0g2OJi%2FzmXHfenomYtn5EW9vzeG8LzfPUwktUBEmkxg5p7bh%2BFbQ%3D&pvid=10_106.6.161.154_3367_1490163222155

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末尤莺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子颤霎,更是在濱河造成了極大的恐慌,老刑警劉巖友酱,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異锤躁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)系羞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來椒振,“玉大人,你說我怎么就攤上這事澎迎。” “怎么了嗡善?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)罩引。 經(jīng)常有香客問我各吨,道長(zhǎng),這世上最難降的妖魔是什么袁铐? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任揭蜒,我火速辦了婚禮,結(jié)果婚禮上剔桨,老公的妹妹穿的比我還像新娘屉更。我一直安慰自己,他們只是感情好洒缀,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布瑰谜。 她就那樣靜靜地躺著,像睡著了一般树绩。 火紅的嫁衣襯著肌膚如雪萨脑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天饺饭,我揣著相機(jī)與錄音渤早,去河邊找鬼。 笑死瘫俊,一個(gè)胖子當(dāng)著我的面吹牛鹊杖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扛芽,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼骂蓖,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了胸哥?” 一聲冷哼從身側(cè)響起涯竟,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后庐船,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體银酬,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年筐钟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片篓冲。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡壹将,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出诽俯,到底是詐尸還是另有隱情暴区,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布房交,位于F島的核電站候味,受9級(jí)特大地震影響负溪,放射性物質(zhì)發(fā)生泄漏济炎。R本人自食惡果不足惜须尚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一耐床、第九天 我趴在偏房一處隱蔽的房頂上張望撩轰。 院中可真熱鬧堪嫂,春花似錦、人聲如沸淹办。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翅萤。三九已至断序,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間漱凝,已是汗流浹背诸迟。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工壁公, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绅项,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓囊陡,卻偏偏與公主長(zhǎng)得像撞反,于是被迫代替她去往敵國(guó)和親遏片。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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