说说 Android 里的 Handler 的机制

简介

Q:什么是 Handler
A:Handler 是 Android 系统里的消息处理机制,下面的一段文字是在 Handler 源码上的注释,它阐述了 Handler 作为消息处理机制的作用。

Handler 是一个可以通过关联一个消息队列来发送或处理消息,Runnable对象。每个Handler都关联一个单个的线程和消息队列.当你创建一个新的Handler的时候它就将被绑定到一个线程或线程上的消息队列,从那时起,这个Handler就将为这个消息队列提供消息或Runnable对象,处理消息队列释放出来的消息或Runnable对象.

Q:Handler 的主要用途
A:(1)能够定时执行消息和Runable对象;(2)可以将一个执行的动作放在不同的线程中。

Q:Handler 的主要用法
A:通过一系列的 post、send 方法发送消息,通过 handleMessage 来处理消息。

post(Runnable r)
postAtTime(Runnable r, long uptimeMillis)
postDelayed(Runnable r, long delayMillis)
sendEmptyMessage(int what)
sendMessage(Message msg)
sendMessageAtTime(Message msg, long uptimeMillis)
sendMessageDelayed(Message msg, long delayMillis) 

Q:与 Handler 相关的一些类
A:与 Handler 相关的主要是 Message,MessageQueue,Looper这些类。

Message:消息的载体。
MessageQueue:消息队列,主要功能是向消息池中投递消息和取走消息。
Looper:线程的消息循环处理器。

深入

Q:各个类的对应关系
A:每个线程只允许包含一个 Looper,每个 Looper 包含一个 MessageQueue。每个线程上可以生成多个Handler,Handler默认使用的是当前线程上的 Looper 。

Q:如何确保每个线程上只有一个 Looper,且各个线程之间互不干扰
A:Looper 类的实例必须通过方法 prepare() 创建,一个线程中多次调用 prepare() 方法将会抛出异常。Looper 实例将会保存在静态变量 ThreadLocal 中,ThreadLocal 实现了线程本地存储的功能,这样放入 ThreadLocal 对象的 Looper 对象就与线程关联在一起。

Q:消息是如何按时间分发的
A:向 MessageQueue 发消息使用的 enqueueMessage 方法,其方法在插入消息时根据时间来排序,时间早的插在前面。消息队列的组织利用了 Message 类中的 next 指针形成一个从头指向尾的单向链表,插入时计算是否需要唤醒处理线程。

// 如果新来的消息时间比队列头的消息短则成为新的队列头,唤醒处理线程
if (p == null || when == 0 || when < p.when) {
    // New head, wake up the event queue if blocked.
    msg.next = p;
    mMessages = msg;
    needWake = mBlocked;
} else {
    ...
}

Q:消息队列是如何挂起,又是如何唤醒的
A:MessageQueue 中的消息循环在方法 next() 中,而挂起和唤醒则是通过 native 层来实现。在 native 层的 Looper 类构造函数中创建了管道,同时使用 epoll 来监听读管道。epoll 的作用是监听管道上的数据,管道则用于线程间通信。

nativePollOnce(ptr, nextPollTimeoutMillis);

在 MessageQueue 的 next() 方法中会调用 nativePollOnce() 方法,该方法最后通过调用 epoll_wait()来执行等待操作。
同样,调用 nativeWake() 可以唤醒处理线程。nativeWake()最终会调用到 native 层的 Looper 类的 wake()方法。wake() 方法通过向管道中写入数据来唤醒消息处理线程。

Q:SyncBarrier 是什么
A:SyncBarrier 或者叫“同步分割栏”,在 MessageQueue 类中有一个方法叫 enqueueSyncBarrier(long when),可以调用这个方法在消息队列中插入一条没有 Handler 对象的消息,这条不带 Handler 对象的消息就称为 “SyncBarrier”(开发者需要调用Looper的postSyncBarrier()来打入)。

SyncBarrier就像一个卡子,卡在消息链表中的某个位置,当消息循环不断从消息链表中摘取消息并进行处理时,一旦遇到那么即使在分割栏之后还有若干已经到时的普通Message,也不会摘取这些消息了。此时如果还有消息需要处理,可以使用 setAsynchronous() 方法给消息做上标志。这也是‘普通Message’和‘异步Message’的区别了。

总结

概括的描述,无非就是通过 Handler 向 Looper 的 MessageQueue 发送 Message 消息,再由 Looper 在消息循环里处理。关于 Android 的消息机制能说的暂时就那么多了,详情可以结合代码源代码细细思考。


一篇更详细的 Handler 机制——聊一聊Android的消息机制

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

推荐阅读更多精彩内容