从 Message 生命看 Handler 框架

Android 系统用 Binder 机制进行进程通信,用 Handler 进行线程通信,本文从 Message 的生命流程看懂 Handler 框架。

1、什么是 Handler 框架?

Handler 框架是 Android 用于线程通信的一种机制,采用消息队列的形式。主要包括消息队列(MessageQueue)、消息发送和处理器(Handler)、消息驱动器(Looper) 以及消息载体(Message)。

2、Handler 是怎样的工作流程?

通过 Handler 将一个 Message 发送给 MessageQueue,Looper 会不断的从 MessageQueue 中取,然后发送给相关联的 Handler 去处理。如上图。

1)Message 的获取是比较自由,可以自己 new,也可以 Message.obtain。Message 内部有一个 static pool,用于重用消息。

2,3)发送消息的方式非常多,最终都会通过 Handler.enqueueMessage 方法将消息添加到消息队列中。在这个过程中 Handler 会为 Message 设置执行时间(when)、处理器(target,就是当前 Handler) 两个关键属性。

4)MessageQueue 会根据 Message.when 在内部队列的排序,将 Message 插在一个合适的位置。MessageQueue 内部是使用单链表的形式实现的队列,便于插入和删除,Message.next 属性。

5,6,7)Looper 是一个驱动器,loop 方法会死循环调用 MessageQueue.next 方法,从消息队列中取消息,然后分发到消息的处理器(Message.targe)。

8,9)至此,这一次通信就完成了,消息会被回收进入池子。

3、延时执行是如何实现的?

1)Message 有一个 when 属性记录消息执行的时间;

2)MessageQueue.next 在取消息的时候,如果发现第一个消息的执行时间还没到或者没有消息可执行,就会阻塞,调用 nativePollOnce 进行休眠,这里会传递一个休眠时间。休眠结束或者有新的消息来到,都会结束休眠,继续取消息。

3)设置 when 属性和 next 方法比较时间的时候,使用的是 SystemClock,这个类记录系统从启动到现在的时间,他不受用户修改时间的影响。

4、线程通信是如何实现的?

每一个线程只会有一个 MessageQueue 和 Looper,他们可以关联非常多的 Handler。你可以在线程 A 通过关联线程 B 的 Handler 发送消息,即可完成通信。Handler 有一个构造方法可以指定 Looper,你只需创建 Handler 的时候指定想要通信线程的 Looper 即可。默认情况下,会使用当前线程关联的 Looper。

这里就要保证每个线程只有一个 Looper,其内部是使用 ThreadLocal 实现。Looper.prepare 方法会先检查当前线程是否已经有了 Looper(通过 ThreadLocal.get),如果没有,创建一个,并保存到 ThreadLocal 中。

5、子线程如何使用 Handler 框架?

Handler 能够工作,主要是当前线程的 Looper 及 MessageQueue 准备好了,所以子线程如果想使用 Handler,调用 Looper.prepare 和 Looper.loop 方法,让当前线程 Looper 和 MessageQueue 工作就好。

6、Android 主线程为什么没有因为 loop 死循环卡死?

谢谢 @Gityuan 老师 的答案。

其实死循环并不会卡死线程,这是属于正常执行的一部分。所谓“卡死”其实是指 UI 卡顿,造成这个问题其实是因为 Handler 执行的某个任务(Message)时间太长,导致后面更新 UI 的任务被阻塞了。这也是为什么不在主线程执行耗时操作的原因。

由此引出的一个问题是为什么只能在主线程更新 UI?根本原因是 View 操作是非线程安全的,如果多线程就会造成 UI 错乱。所以解决线程安全有两个方向,一是将 View 写成线程安全,二是在一个线程里执行。

7、其他

1)消息队列主要使用了生产者消费者的设计模式,因此消息队列(MessageQueue)保证了线程安全。

2)附上一篇非常好的 Handler 源码解析文章。

感谢 @Ruheng 老师 的博客。

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