Android Handler 消息机制
Handler 消息机制是 Android 中线程间通信的重要手段,主要功能是在子线程中发起的任务切换至主线程执行。
核心组成部分
- Handler:消息的发送与处理者,提供 sendMessage() 发送消息、handleMessage() 处理消息的功能。
- MessageQueue:消息队列,以链表形式存储消息,按时间顺序先进先出(FIFO)排列。
- Looper:消息循环器,绑定当前线程,通过 loop() 方法无限循环从 MessageQueue 获取消息,并交给对应的 Handler 处理。
- ThreadLocal:用于存储线程专属的 Looper,保证每个线程只有一个 Looper 实例。
核心工作流程
- 初始化:主线程默认创建 Looper,子线程需要手动调用 Looper.prepare() 创建 Looper 并绑定到当前线程,然后通过 Looper.loop() 启动循环。
- 发送消息:Handler 通过 sendMessage() 或 post(Runnable),将消息(或 Runnable 封装成的消息)加入 MessageQueue。
- 循环取消息:Looper 的 loop() 方法持续从 MessageQueue 中获取消息,若队列为空则阻塞等待。
- 处理消息:Looper 获取到消息后,调用该消息对应的 Handler 的 dispatchMessage() 方法,最终触发 handleMessage() 或 Runnable 的 run() 方法。
关键特性
- 线程绑定:Looper 与其创建的线程绑定,Handler 发送的消息在 Looper 所在线程处理。
- 内存注意:避免 Handler 匿名内部类引起的内存泄漏,推荐使用静态内部类 + 弱引用,或在页面销毁时清除未处理的消息。
- 消息优先级:Message 可通过 arg1、arg2 携带简单数据,what 用于标识消息类型,支持设置 when 来指定延迟执行时间。
Handler 机制 Kotlin 核心源码
以下是 Handler 消息机制核心组件的 Kotlin 简化实现。
- ThreadLocal 线程专属存储:
/** * 线程本地存储:确保每个线程仅持有一个目标实例(此处用于存储 Looper) */ class ThreadLocal<T> { // 用 HashMap 模拟线程与实例的映射(真实源码为 native 实现,此处简化) private val threadMap = mutableMapOf<Thread, T>() // 获取当前线程的存储实例 fun get(): T? = threadMap[Thread.currentThread()] // 存储当前线程的实例 fun set(value: T) { threadMap[Thread.currentThread()] = value } // 移除当前线程的存储实例 fun remove() { threadMap.remove(Thread.currentThread()) } } - Message 消息实体:
/** * 消息实体:存储 Handler、执行任务、延迟时间等核心信息 */ class Message { var what: Int = 0 // 消息标识(区分不同消息) var arg1: Int = 0 // 携带简单 int 数据 var arg2: Int = 0 // 携带简单 int 数据 var obj: Any? = null // 携带复杂对象数据 var `when`: Long = 0 // 消息执行时间(SystemClock.uptimeMillis() + 延迟时间) var target: Handler? = null // 关联的 Handler(最终处理消息的对象) var callback: Runnable? = null // 直接执行的任务(post(Runnable) 时封装) var next: Message? = null // 链表下一个消息(MessageQueue 用) // 消息池复用(避免频繁创建对象,优化性能) private companion object { private val sPool = mutableListOf<Message>() private const val MAX_POOL_SIZE = 50 // 消息池最大容量 // 获取复用消息(优先从池子里拿,无则新建) fun obtain(): Message { synchronized(sPool) { return if (sPool.isNotEmpty()) sPool.removeAt(0) else Message() } } // 回收消息到池子里 }
ThreadLocal
fun recycle(msg: Message) {
// 清空消息状态,防止内存泄漏
msg.what = 0
msg.arg1 = 0
msg.arg2 = 0
msg.obj = null
msg.`when` = 0
msg.target = null
msg.callback = null
msg.next = null
synchronized(sPool) {
if (sPool.size < MAX_POOL_SIZE) {
sPool.add(msg)
}
}
}
}
3. MessageQueue 消息队列
/**
* 消息队列:以链接形式存储 Message,按 when 时间排序(FIFO+延迟优先级)
*/
class MessageQueue(private val quitAllowed: Boolean) {
internal var head: Message? = null // 链表头节点(简化实现:链表确保插入/删除效率)
private var isQuitted = false // 队列是否已退出
/**
* 插入消息到队列(按 when 时间升序排序)
*/
fun enqueueMessage(msg: Message): Boolean {
if (isQuitted) throw IllegalStateException("MessageQueue has been quitted")
if (msg.target == null) throw IllegalArgumentException("Message target must not be null")
synchronized(this) {
// 消息已被回收,直接返回失败
if (msg.`when` == 0L && msg.target == null) return false
val currentTime = SystemClock.uptimeMillis()
val p = head
if (p == null || msg.`when` < p.`when`) {
// 插入到链表头部(当前消息最早执行)
msg.next = p
head = msg
} else {
// 寻找插入位置(按 when 升序排列)
var prev = p
var curr = p.next
while (curr != null && curr.`when` <= msg.`when`) {
prev = curr
curr = curr.next
}
msg.next = curr
prev?.next = msg
}
// 唤醒阻塞的 Looper.loop()(模拟 native 层唤醒逻辑)
(this as Object).notify()
return true
}
}
/**
* 取出消息(阻塞式:队列空时等待,有消息且到执行时间时返回)
*/
fun next(): Message? {
var nextPollTimeoutMillis = -1 // -1 表示无限阻塞
while (true) {
synchronized(this) {
val currentTime = SystemClock.uptimeMillis()
var msg = head
if (msg != null) {
// 消息未到执行时间,计算阻塞时长
if (currentTime < msg.`when`) {
nextPollTimeoutMillis = (msg.`when` - currentTime).toInt()
} else {
// 取出消息并从链表移除
head = msg.next
msg.next = null
return msg
}
} else {
// 队列空,无限阻塞
nextPollTimeoutMillis = -1
}
// 退出队列:返回 null 终止 Looper.loop()
if (isQuitted) return null
}
// 阻塞线程(模拟 nativePollOnce,实际源码用 Linux 管道/epoll)
Thread.sleep(if (nextPollTimeoutMillis > 0) nextPollTimeoutMillis.toLong() else 10)
}
}
/**
* 退出消息队列(主线程 Looper 不允许退出)
*/
fun quit(): Boolean {
if (!quitAllowed) throw IllegalStateException("Main Looper cannot quit")
synchronized(this) {
if (isQuitted) return false
isQuitted = true
(this as Object).notify() // 激活阻塞的 next()
return true
}
}
}
4. Looper 消息循环器
/**
* 消息循环器:关联线程,无限循环从 MessageQueue 获取消息并分发
*/
class Looper private constructor(private val quitPermitted: Boolean) {
val messageQueue: MessageQueue = MessageQueue(quitPermitted) // 相关的消息队列
val thread: Thread = Thread.currentThread() // 关联当前创建的线程
companion object {
private val sThreadLocal = ThreadLocal<Looper>() // 线程专属 Looper 存储
private var sMainLooper: Looper? = null // 主线程 Looper(全局唯一)
/**
* 主线程初始化 Looper(系统在 ActivityThread.main() 中调用,无需开发者手动调用)
*/
fun prepareMainLooper() {
prepare(false) // 主线程 Looper 不允许退出(quitPermitted=false)
synchronized(Looper::class.java) {
if (sMainLooper != null) throw IllegalStateException("主线程 Looper 已经初始化")
sMainLooper = myLooper()
}
}
/**
* 子线程创建 Looper(必须在 loop() 前调用)
*/
fun prepare() {
prepare(true) // 子线程 Looper 允许退出
}
private fun prepare(quitPermitted: Boolean) {
// 每个线程只能创建一个 Looper,重复调用抛异常
if (sThreadLocal.get() != null) {
throw RuntimeException("每个线程只能创建一个 Looper")
}
sThreadLocal.set(Looper(quitPermitted))
}
/**
* 启动消息循环(无限循环,直到 MessageQueue.next() 返回 null 终止)
*/
fun loop() {
val looper = myLooper() ?: throw RuntimeException("没有 Looper;Looper.prepare() 未在此线程上调用")
val queue = looper.messageQueue
// 无限循环取消息、分发消息
while (true) {
val msg = queue.next() ?: break // 队列退出,终止循环
try {
// 关键:将消息分发给相关的 Handler
msg.target?.dispatchMessage(msg)
} finally {
// 回收消息到消息池
Message.recycle(msg)
}
}
}
/**
* 获取当前线程的 Looper
*/
fun myLooper(): Looper? = sThreadLocal.get()
/**
* 获取主线程 Looper
*/
fun getMainLooper(): Looper = sMainLooper ?: throw IllegalStateException("主线程 Looper 未初始化")
}
}
5. Handler 消息发送/处理器
/**
* 消息发送者+处理器:负责将消息发送到队列,接收 Looper 分发的消息并处理
*/
class Handler(
looper: Looper = Looper.myLooper() ?: throw RuntimeException("没有 Looper;Handler 需要一个 Looper")
) {
private val looper: Looper = looper
private val messageQueue: MessageQueue = looper.messageQueue
/**
* 发送消息(直接入队)
*/
fun sendMessage(msg: Message): Boolean {
msg.target = this // 绑定当前 Handler(Looper 分发时使用)
return messageQueue.enqueueMessage(msg)
}
/**
* 发送延迟信息(计算 when 时间后入队)
*/
fun sendMessageDelayed(msg: Message, delayMillis: Long): Boolean {
if (delayMillis < 0) throw IllegalArgumentException("延时必须非负")
msg.`when` = SystemClock.uptimeMillis() + delayMillis
return sendMessage(msg)
}
/**
* 发送 Runnable 任务(封装为信息)
*/
fun post(runnable: Runnable): Boolean {
val msg = Message.obtain()
msg.callback = runnable // 绑定需执行的 Runnable
return sendMessage(msg)
}
/**
* 发送延迟 Runnable 任务
*/
fun postDelayed(runnable: Runnable, delayMillis: Long): Boolean {
val msg = Message.obtain()
msg.callback = runnable
msg.`when` = SystemClock.uptimeMillis() + delayMillis
return sendMessage(msg)
}
/**
* 消息分发(Looper.loop() 中调用)
*/
fun dispatchMessage(msg: Message) {
// 执行优先级:1. Runnable 回调 -> 2. handleMessage()
if (msg.callback != null) {
msg.callback?.run() // 执行 post 的 Runnable
} else {
handleMessage(msg) // 执行自定义信息处理
}
}
/**
* 自定义消息处理(子类重写)
*/
open fun handleMessage(msg: Message) {}
/**
* 移除未处理的特定标识信息
*/
fun removeMessages(what: Int) {
synchronized(messageQueue) {
var prev: Message? = null
var curr = messageQueue.head
while (curr != null) {
if (curr.target == this && curr.what == what) {
// 从链表中移除信息
if (prev == null) {
messageQueue.head = curr.next
} else {
prev.next = curr.next
}
Message.recycle(curr)
curr = prev?.next ?: messageQueue.head
} else {
prev = curr
curr = curr.next
}
}
}
}
}
6. 用法示例(线程间通信)
fun main() {
// 1. 主线程初始化 Looper(真实 Android 中系统自动调用)
Looper.prepareMainLooper()
val mainHandler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
// 运行在主线程
println("主线程处理信息:what=${msg.what}, arg1=${msg.arg1}, 线程=${Thread.currentThread().name}")
}
}
// 2. 子线程发送信息到主线程
Thread({
println("子线程发送信息:线程=${Thread.currentThread().name}")
// 发送普通信息
val msg1 = Message.obtain()
msg1.what = 1
msg1.arg1 = 100
mainHandler.sendMessage(msg1)
// 发送延迟信息(1秒后执行)
val msg2 = Message.obtain()
msg2.what = 2
msg2.arg1 = 200
mainHandler.sendMessageDelayed(msg2, 1000)
// 发送 Runnable 任务
mainHandler.post {
println("主线程执行 Runnable:线程=${Thread.currentThread().name}")
}
}, "辅助线程-发送者").start()
// 3. 启动主线程消息循环(暂停当前线程,无限循环)
Looper.loop()
}
核心要点总结
线程关联
:通过
ThreadLocal
确保每个线程仅一个
Looper
,
Handler
关联
Looper
后,消息在
Looper
所在线程处理。
重复使用机制
:
Message
池通过
obtain()
重复利用、
recycle()
回收,避免频繁生成对象。
阻塞与激活
:
MessageQueue.next()
暂停等待消息,
enqueueMessage()
激活线程取消息。
内存泄漏预防
:
用静态内部类+弱引用实现
Handler
,防止持有 Activity 引用。
页面销毁时调用
removeMessages()
移除未处理消息。


雷达卡


京公网安备 11010802022788号







