一切从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硬核知识点。

                                                   

                                                                     欢迎转发,关注公众号

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