一切从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技术的同学,欢迎加微信公众号 xh18310039919。用诙谐的方式学习Android硬核知识点。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容

  • 近几年,韩国的综艺节目越来越备受瞩目,最初由湖南卫视引进的MBC《爸爸!我们去哪儿》获得了爆发性的反应后,更多的韩...
    简单的亲故阅读 18,363评论 5 12
  • 现在是半夜12点,我的眼睛已经充血发红,阵阵倦意袭来,但是头疼的无法入睡。最近好失败,感觉久像坠入无底洞,身边的人...
    狄仁杰义士阅读 181评论 0 0
  • 小时候有个梦想 梦想图书馆为工作场 每天沉浸在书的海洋 看一看世界的模样 领略故事里的风光 长大了有个梦想 梦想能...
    星空4546阅读 248评论 1 7
  • 新颠峰小学生训练营结束,已是下午七点多。我们全家走在返程的路上,考虑到五一节堵车的问题,第二天下午孩子还要返校...
    杜海斌十杜锦恒阅读 246评论 1 2