Android开发日记(十九)——说说 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 来处理消息。

1
2
3
4
5
6
7
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 指针形成一个从头指向尾的单向链表,插入时计算是否需要唤醒处理线程。

1
2
3
4
5
6
7
8
9
// 如果新来的消息时间比队列头的消息短则成为新的队列头,唤醒处理线程
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 的作用是监听管道上的数据,管道则用于线程间通信。

1
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的消息机制