Handler机制的深入解析
在Android开发中,Handler机制是线程间通信的核心,其实现依赖于 Looper、MessageQueue 和 Message 的协同工作。下面我将从 Looper 的工作机制开始,逐步深入解释整个消息传递的流程。
1. Looper 的核心作用
Looper 是消息循环的核心,负责从 MessageQueue 中取出消息并分发给 Handler 进行处理。每个线程只能有一个 Looper,它通过 ThreadLocal
存储在本线程中。
Looper 的初始化:
Looper.prepare()
:- 初始化 Looper,创建 MessageQueue。
- 将 Looper 实例通过
ThreadLocal
存储到线程的ThreadLocalMap
中。 - 每个线程只能调用一次
Looper.prepare()
,否则会抛出异常。
Looper 的消息循环:
Looper.loop()
:- 通过
Looper.myLooper()
获取当前线程的 Looper 实例。 - 从 Looper 中获取 MessageQueue,并调用
queue.next()
方法获取消息。- 如果消息的
target
(即 Handler)为空,说明是消息屏障(Barrier Message)。 - 如果消息设置了
async
标志,则认为是异步消息;否则为同步消息。 - 如果当前队列中没有消息,则线程进入休眠状态(基于
epoll
机制)。 - 如果有消息但未到执行时间,则线程有限等待(
timed wait
)。 - 如果队列空闲,执行
IdleHandler
的回调。
- 如果消息的
- 通过
Looper 的退出:
Looper.quit()
:- 分为
quitSafely()
和quit()
。quitSafely()
:清空所有未执行的消息,保留当前正在处理的消息。quit()
:直接清空所有消息,包括正在处理的消息。
- 只有创建 Looper 时允许退出(
quitAllowed
为 true)才能执行。
- 分为
2. Handler 的作用
Handler 是工具类,用于发送和处理消息。它与 Looper 关联,进而持有 MessageQueue。
Handler 的工作流程:
-
初始化:
- Handler 在创建时持有当前线程的 Looper 和 MessageQueue。
- 如果线程没有 Looper,创建 Handler 时会抛出异常。
-
发送消息:
- 无论是
sendMessage()
还是post()
系列方法,最终都会调用 MessageQueue 的enqueueMessage()
方法,将消息插入队列。
- 无论是
-
处理消息:
- 从 MessageQueue 取出的消息会通过
msg.target
(即发送该消息的 Handler)回调到dispatchMessage()
方法。- 如果消息中有
callback
(如Runnable
),则直接执行callback.run()
。 - 否则,调用
handleMessage()
方法进行处理(通常需要开发者重写)。
- 如果消息中有
- 从 MessageQueue 取出的消息会通过
3. MessageQueue 的实现
MessageQueue 是消息队列,底层由 Native 层实现,采用 epoll
机制来管理线程的休眠和唤醒。
消息的入队:
- 当 Handler 发送消息时,根据消息的
when
字段,遍历队列找到合适的位置插入。 - 如果当前队列处于休眠状态且有新消息入队,则唤醒线程。
消息的取出:
- 如果队列中没有消息,线程进入休眠状态。
- 如果有消息但未到执行时间,线程等待。
- 如果队列空闲,执行
IdleHandler
的回调。
4. Message 的类型
Message 是消息的载体,有三类:
- 同步消息:普通消息,按照时间顺序被处理。
- 异步消息:设置
async
标志,优先于同步消息执行。 - 消息屏障(Barrier Message):
- 无
target
,用于屏蔽同步消息,保证异步消息的优先级。 - 常用于系统级操作,如页面刷新(
ViewRootImpl
中的Choreographer
)。
- 无
Message 的复用:
- Message 支持资源复用,通过
obtain()
方法从线程的 Message Pool 中获取。 - Message Pool 的上限为 50。
5. Handler 机制的总结
- Looper:负责消息循环,与线程绑定。
- MessageQueue:存储消息,基于
epoll
机制管理线程的休眠和唤醒。 - Handler:发送和处理消息的工具类。
- Message:消息的载体,支持同步、异步和消息屏障。
整个机制的协同工作,保证了 Android 应用的高效线程通信和 UI 更新。