一切從android的handler說起(六)之四大組件生命周期起源

閱讀本文大概需要 4 分鐘。

?

上一篇,我們了解到Android里觸摸事件是如何一步一步轉(zhuǎn)入U(xiǎn)I線程的message queue里被執(zhí)行的,這種事件是由外部事件觸發(fā)的。

我接著對(duì)小張說:其實(shí)Android里還有一種UI queue里的事件更為大家熟知,你天天寫代碼都在與之打交道,你知道嗎?

小張有些丈二和尚摸不著頭腦,想了一會(huì)兒問道:能給一些提示嗎?

我提示道:它是Android系統(tǒng)框架層產(chǎn)生的事件,你在四大組件上寫的代碼均無法逃脫它的掌控!

小張雖然不是很清楚為什么,但是由于提示太明顯,問道:你說的難道是四大組件的生命周期?

我肯定道:沒錯(cuò),比如你天天寫Activity,在其onCreate, onResume等生命周期里寫業(yè)務(wù)代碼,那你知道四大組件的生命周期是怎么來的嗎?

小張懷疑到:難道它們也是handler消息機(jī)制觸發(fā)的嗎?

我說道:你沒有聽錯(cuò)!就連四大組件的生命周期也遵循了這個(gè)事件驅(qū)動(dòng)模型,它們均是由Android系統(tǒng)框架層產(chǎn)生相應(yīng)的message扔進(jìn)UI queue觸發(fā)的。

小張緊接著問道:如果這樣的話,UI線程里必然存在一個(gè)handler在處理對(duì)應(yīng)的message,以辨別這個(gè)message是哪個(gè)組件,是什么生命周期階段。

我點(diǎn)了點(diǎn)頭,道:你說得沒錯(cuò)!你在Android源碼里見過這個(gè)handler嗎?

小張搖了搖頭:我平時(shí)業(yè)務(wù)做得比較多,對(duì)Android系統(tǒng)框架層的源碼看得比較少。

我聽了后說道:那你平時(shí)可得多關(guān)注關(guān)注一些底層原理類的東西了,業(yè)務(wù)是永遠(yuǎn)在變動(dòng),而越是底層的東西越是相對(duì)穩(wěn)定的,只有弄清楚基礎(chǔ)才能知其所以然,更好的為業(yè)務(wù)服務(wù)。

小張聽后,連忙點(diǎn)頭:你說得是,回去一定惡補(bǔ)這塊短板。

我繼續(xù)說道:好了,Android源碼里有個(gè)ActivityThread內(nèi)部類H就是剛才所說的handler了,你看看它的源碼,你就知道它都在干些什么了。

1private?final?class?H?extends?Handler?{

2????...

3????public?void?handleMessage(Message?msg)?{

4????????????if?(DEBUG_MESSAGES)?Slog.v(TAG,?">>>?handling:?"?+?msg.what);

5

6??????????????switch?(msg.what)?{

7

8????????????????case?LAUNCH_ACTIVITY:?{

9????????????????????ActivityClientRecord?r?=?(ActivityClientRecord)msg.obj;

10????????????????????r.packageInfo?=?getPackageInfoNoCheck(r.activityInfo.applicationInfo);

11????????????????????handleLaunchActivity(r,?null);

12????????????????}?

13????????????????????break;

14

15????????????????case?RELAUNCH_ACTIVITY:?{

16????????????????????ActivityClientRecord?r?=?(ActivityClientRecord)msg.obj;

17????????????????????handleRelaunchActivity(r);

18????????????????}?

19????????????????????break;

20

21????????????????case?PAUSE_ACTIVITY:

22????????????????????handlePauseActivity((IBinder)msg.obj,?false,?msg.arg1?!=?0,?msg.arg2);

23????????????????????maybeSnapshot();

24????????????????????break;

25

26????????????????case?PAUSE_ACTIVITY_FINISHING:

27????????????????????handlePauseActivity((IBinder)msg.obj,?true,?msg.arg1?!=?0,?msg.arg2);

28????????????????????break;

29

30????????????????case?STOP_ACTIVITY_SHOW:

31????????????????????handleStopActivity((IBinder)msg.obj,?true,?msg.arg2);

32????????????????????break;

33

34????????????????case?STOP_ACTIVITY_HIDE:

35????????????????????handleStopActivity((IBinder)msg.obj,?false,?msg.arg2);

36????????????????????break;

37????????????????????...

38????????????????case?RESUME_ACTIVITY:

39????????????????????handleResumeActivity((IBinder)msg.obj,?true,?msg.arg1?!=?0);

40????????????????????break;

41????????????????case?SEND_RESULT:

42????????????????????handleSendResult((ResultData)msg.obj);

43????????????????????break;

44????????????????case?DESTROY_ACTIVITY:

45????????????????????handleDestroyActivity((IBinder)msg.obj,?msg.arg1?!=?0,msg.arg2,?false);

46????????????????????break;

47????????????????????...

48????????????????case?NEW_INTENT:

49????????????????????handleNewIntent((NewIntentData)msg.obj);

50????????????????????break;

51????????????????case?RECEIVER:

52????????????????????handleReceiver((ReceiverData)msg.obj);

53????????????????????maybeSnapshot();

54????????????????????break;

55????????????????case?CREATE_SERVICE:

56????????????????????handleCreateService((CreateServiceData)msg.obj);

57????????????????????break;

58????????????????case?BIND_SERVICE:

59????????????????????handleBindService((BindServiceData)msg.obj);

60????????????????????break;

61????????????????case?UNBIND_SERVICE:

62????????????????????handleUnbindService((BindServiceData)msg.obj);

63????????????????????break;

64????????????????????...

65????????????????case?STOP_SERVICE:

66????????????????????handleStopService((IBinder)msg.obj);

67????????????????????maybeSnapshot();

68????????????????????break;

69????????????????????...

70????????????}

71????????????if?(DEBUG_MESSAGES)?Slog.v(TAG,?"<<<?done:?"?+?msg.what);

72????????}

73????????...

74}

從上面的代碼,我們可以清晰的看到四大組件的生命周期函數(shù)調(diào)用赫然在列!

小張看了代碼后發(fā)問了:我看到Activity生命周期相應(yīng)的每個(gè)msg.obj前面都用了IBinder進(jìn)行了強(qiáng)轉(zhuǎn),是不是說明這些message都不是App自己進(jìn)程里產(chǎn)生扔過來的?

我笑道:你的眼力不錯(cuò)嘛。這就問到message的事件來源問題了,你說的不錯(cuò),你平時(shí)打開一個(gè)Activity都有哪些方式?

小張說道:要么顯示,要么隱式的startActivity。

我繼續(xù)問道:嗯,那你知道這個(gè)過程大概是怎么樣的嗎?

小張說道:這個(gè)我知道,用戶App會(huì)通過Binder IPC通信詢問AMS(ActivityManagerService),向其索要滿足條件的Activity。

我說道:沒錯(cuò),我們知道AMS是在系統(tǒng)的SystemServer進(jìn)程中,統(tǒng)管Android上的所有Activity(這又是典型解耦手段--集中管理的HUB思想)。當(dāng)找到了對(duì)應(yīng)的Activity之后,由于跨進(jìn)程,就通過Binder IPC手段來通知用戶App進(jìn)程所在的UI線程來打開對(duì)應(yīng)的Activity。

小張接道:所以,AMS就把這種意圖打包進(jìn)message里,通過Binder IPC扔進(jìn)UI線程的message queue中[注],當(dāng)UI線程喚醒時(shí),取出message交由H實(shí)例handler處理時(shí),就進(jìn)入了上述代碼的switch case分支,發(fā)現(xiàn)了是LAUNCH_ACTIVITY,就調(diào)用handleLaunchActivity處理邏輯,其中就嵌入了Activity的onCreate, onStart調(diào)用,預(yù)留給開發(fā)者重寫具體的業(yè)務(wù)邏輯。

我哈哈笑道:你都學(xué)會(huì)搶答了,進(jìn)步很快啊,孺子可教也。所以你看,為什么平時(shí)說在UI線程的生命周期做繁重的耗時(shí)任務(wù)會(huì)導(dǎo)致UI卡頓或者ANR?

小張答道:由于任何UI線程的業(yè)務(wù)代碼均逃離不了組件的生命周期,而生命周期又源于UI queue中的message的處理,所以如果在任何一個(gè)生命周期做了耗時(shí)任務(wù),這會(huì)導(dǎo)致queue中后面的message無法得到及時(shí)的處理,所以看起來就是有反應(yīng)延時(shí),也就是視覺上的卡頓,嚴(yán)重的會(huì)長時(shí)間得不到處理,從而導(dǎo)致ANR的發(fā)生。

我肯定的點(diǎn)了點(diǎn)頭:你看,底層原理一通百通,平時(shí)Android開發(fā)時(shí)要遵循的在這里得到了真實(shí)的解答,是不是感覺理解更加深刻了?

小張興奮的說道:是啊,知道了為什么之后,感覺有種入木三分的感覺,以后在開發(fā)中就絕對(duì)不會(huì)犯這樣的錯(cuò)誤了。

最后我又繼續(xù)補(bǔ)充道:其實(shí)這其中也蘊(yùn)含了一種設(shè)計(jì)思想。當(dāng)你想設(shè)計(jì)一套底層框架系統(tǒng),而且又希望上層應(yīng)用遵循你的規(guī)則,就需要預(yù)留這樣的接口或者抽象函數(shù),以供開發(fā)者來具體實(shí)現(xiàn)。

小張說道:這就是依賴倒置思想吧?

我說道:是的。其實(shí)Android系統(tǒng)源碼里有大量的設(shè)計(jì)模式的運(yùn)用,有機(jī)會(huì)可以好好看看。

小張:嗯,看來底層原理還挺有意思的,弄懂后還能加強(qiáng)對(duì)上層應(yīng)用的理解,真是非常有必要系統(tǒng)性的學(xué)習(xí)了。

[注]:這里AMS其實(shí)并不是和UI線程直接打交道,而是通過App端的Binder線程,然后再傳遞給UI線程。如下圖:

?

有熱愛Android技術(shù)的同學(xué),歡迎加微信公眾號(hào) xh18310039919。用詼諧的方式學(xué)習(xí)Android硬核知識(shí)點(diǎn)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 近幾年,韓國的綜藝節(jié)目越來越備受矚目,最初由湖南衛(wèi)視引進(jìn)的MBC《爸爸!我們?nèi)ツ膬骸帆@得了爆發(fā)性的反應(yīng)后,更多的韓...
    簡單的親故閱讀 19,698評(píng)論 5 12
  • 現(xiàn)在是半夜12點(diǎn),我的眼睛已經(jīng)充血發(fā)紅,陣陣倦意襲來,但是頭疼的無法入睡。最近好失敗,感覺久像墜入無底洞,身邊的人...
    狄仁杰義士閱讀 212評(píng)論 0 0
  • 小時(shí)候有個(gè)夢想 夢想圖書館為工作場 每天沉浸在書的海洋 看一看世界的模樣 領(lǐng)略故事里的風(fēng)光 長大了有個(gè)夢想 夢想能...
    星空4546閱讀 269評(píng)論 1 7
  • 新顛峰小學(xué)生訓(xùn)練營結(jié)束,已是下午七點(diǎn)多。我們?nèi)易咴诜党痰穆飞希紤]到五一節(jié)堵車的問題,第二天下午孩子還要返校...
    杜海斌十杜錦恒閱讀 282評(píng)論 1 2

友情鏈接更多精彩內(nèi)容