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

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

 

 

上一篇,我們瞭解到Android裏觸摸事件是如何一步一步轉入UI線程的message queue裏被執行的,這種事件是由外部事件觸發的。

 

我接着對小張說:其實Android裏還有一種UI queue裏的事件更爲大家熟知,你天天寫代碼都在與之打交道,你知道嗎?

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

 

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

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

 

我肯定道:沒錯,比如你天天寫Activity,在其onCreate, onResume等生命週期裏寫業務代碼,那你知道四大組件的生命週期是怎麼來的嗎?

小張懷疑到:難道它們也是handler消息機制觸發的嗎?

 

我說道:你沒有聽錯!就連四大組件的生命週期也遵循了這個事件驅動模型,它們均是由Android系統框架層產生相應的message扔進UI queue觸發的。

 

小張緊接着問道:如果這樣的話,UI線程裏必然存在一個handler在處理對應的message,以辨別這個message是哪個組件,是什麼生命週期階段。

 

我點了點頭,道:你說得沒錯!你在Android源碼裏見過這個handler嗎?

小張搖了搖頭:我平時業務做得比較多,對Android系統框架層的源碼看得比較少。

 

我聽了後說道:那你平時可得多關注關注一些底層原理類的東西了,業務是永遠在變動,而越是底層的東西越是相對穩定的,只有弄清楚基礎才能知其所以然,更好的爲業務服務。

小張聽後,連忙點頭:你說得是,回去一定惡補這塊短板。

 

我繼續說道:好了,Android源碼裏有個ActivityThread內部類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}

 

從上面的代碼,我們可以清晰的看到四大組件的生命週期函數調用赫然在列!

 

小張看了代碼後發問了:我看到Activity生命週期相應的每個msg.obj前面都用了IBinder進行了強轉,是不是說明這些message都不是App自己進程裏產生扔過來的?

 

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

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

 

我繼續問道:嗯,那你知道這個過程大概是怎麼樣的嗎?

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

 

我說道:沒錯,我們知道AMS是在系統的SystemServer進程中,統管Android上的所有Activity(這又是典型解耦手段--集中管理的HUB思想)。當找到了對應的Activity之後,由於跨進程,就通過Binder IPC手段來通知用戶App進程所在的UI線程來打開對應的Activity。

 

小張接道:所以,AMS就把這種意圖打包進message裏,通過Binder IPC扔進UI線程的message queue中[注],當UI線程喚醒時,取出message交由H實例handler處理時,就進入了上述代碼的switch case分支,發現了是LAUNCH_ACTIVITY,就調用handleLaunchActivity處理邏輯,其中就嵌入了Activity的onCreate, onStart調用,預留給開發者重寫具體的業務邏輯。

 

我哈哈笑道:你都學會搶答了,進步很快啊,孺子可教也。所以你看,爲什麼平時說在UI線程的生命週期做繁重的耗時任務會導致UI卡頓或者ANR?

 

小張答道:由於任何UI線程的業務代碼均逃離不了組件的生命週期,而生命週期又源於UI queue中的message的處理,所以如果在任何一個生命週期做了耗時任務,這會導致queue中後面的message無法得到及時的處理,所以看起來就是有反應延時,也就是視覺上的卡頓,嚴重的會長時間得不到處理,從而導致ANR的發生。

 

我肯定的點了點頭:你看,底層原理一通百通,平時Android開發時要遵循的在這裏得到了真實的解答,是不是感覺理解更加深刻了?

 

小張興奮的說道:是啊,知道了爲什麼之後,感覺有種入木三分的感覺,以後在開發中就絕對不會犯這樣的錯誤了。

 

最後我又繼續補充道:其實這其中也蘊含了一種設計思想。當你想設計一套底層框架系統,而且又希望上層應用遵循你的規則,就需要預留這樣的接口或者抽象函數,以供開發者來具體實現。

 

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

我說道:是的。其實Android系統源碼裏有大量的設計模式的運用,有機會可以好好看看。

 

小張:嗯,看來底層原理還挺有意思的,弄懂後還能加強對上層應用的理解,真是非常有必要系統性的學習了。

 

[注]:這裏AMS其實並不是和UI線程直接打交道,而是通過App端的Binder線程,然後再傳遞給UI線程。如下圖:

 


有熱愛Android技術的同學,歡迎加 QQ羣 726464410,或者掃描QQ羣二維碼 和 微信公衆號二維碼。用詼諧的方式學習Android硬核知識點。

                                                   

                                                                     歡迎轉發,關注公衆號

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章