Handler 是一个用于处理多线程异步消息的机制,主要用于线程间通信,常见应用场景为 IO 线程获取信息,需要更新 UI 线程进行界面刷新。
Handler 由多个模块组合而成,分别为:
- Message:代表需要传递的消息,每个消息都有自己的标签。
- MessageQueue:消息队列,通过一个单链表的数据结构来维护消息列表。
- Handler:消息处理者,负责向 MessageQueue 发送消息,处理相应的消息事件。
- Looper:消息分发者,负责不断循环执行 Looper.loop 将 MessageQueue 中的消息读取出来,分发给接收者进行处理 Message。
原理

Handler.sendMessage 发送消息到消息队列 MessageQueue,然后 Looper 调用自己的 loop() 函数带动 MessageQueue,从而轮询 MessageQueue 里面的每个 Message,当 Message 达到了可以执行的时间时开始执行,执行后就会调用 Message 绑定的 Handler 来处理消息。
每个线程只存在一个 Looper 对象,Looper 构造函数中创建了 MessageQueue 对象,因此一个线程只有一个 MessageQueue,但可以有多个 Handler。
Looper 死循环不会导致应用卡死吗?
Looper 的死循环并不是无意义的空转,而是基于事件驱动的,它通过 MessageQueue 不断检查是否有新消息需要处理。如果没有消息,线程会进入等待状态,不会占用 CPU 资源。当 MessageQueue 为空时,Looper 使线程进入阻塞状态。当有新消息加入队列时,线程会被唤醒并继续处理消息。这种机制避免了无意义的 CPU 占用。虽然 Looper 是一个死循环,但它通过消息机制高效地处理任务,不会导致卡顿。
子线程之间的通信
不能在子线程直接创建 Handler,因为 Handler 的工作依赖于 Looper,而 Looper 又属于某一个线程的,其他线程不能访问,所以在线程中使用 Handler 时必须要保证当前线程中 Looper 对象并且启动循环,不然会抛出异常。
这里在一个子线程中创建 Handler
var handler: Handler? = null
thread {
Looper.prepare()
handler = object : Handler(Looper.myLooper()!!) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when (msg.what) {
1 -> Log.i(TAG, "Message received: ${msg.obj}")
}
}
}
Looper.loop()
}
然后在另一个子线程中发送消息,注意要确保上面的 Handler 创建完成后再执行消息发送。
thread {
val msg = Message.obtain() //从全局池中返回一个 Message 实例,避免多次创建 Message
msg.what = 1
msg.obj = "My Message"
handler?.sendMessage(msg)
}
HandlerThread
如果想创建一个子线程的 Handler,在 handlerMessage 方法里处理异步任务的话,使用 HandlerThread 才是最优选。
HandlerThread 本质上是一个线程类,它继承 Thread,有自己内部的 Looper 对象,可进行 Looper 循环。通过获取 HandlerThread 的 Looper 对象传递给 Handler 对象,可以在 handleMessage 方法中执行异步任务,需要注意的是,创建 HandlerThread 后必须先调用 HandlerThread.start() 方法,Thread 会先调用 run 方法,创建 Looper 对象。
val task = Runnable {
//执行异步任务
}
val handlerThread = HandlerThread("name") //参数为线程名
handlerThread.start()
val handler = Handler(handlerThread.looper)
handler.postDelayed(task, 1000)
主线程和子线程的通信
在 App 启动时系统会默认启动了一个主线程的 Looper,所以主线程无需再创建 Looper 对象
private val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when (msg.what) {
1 -> Log.i(TAG, "Message received: ${msg.obj}")
}
}
}
在子线程中发送消息
thread {
val msg = Message.obtain()
msg.obj = "My Message"
msg.what = 1
handler.sendMessage(msg)
}
我们也可以直接使用 post 方法,比如在子线程中操作,需要在主线程中更新 UI
thread {
//子线程操作
handler.post {
//更新 UI
textView.text = data
}
}
延迟执行
我们可以调用 postDelayed 方法做延迟操作,比如延迟 2 秒
handler.postDelayed({
// handler 在哪个线程创建就在哪个线程执行
}, 2000)
如果想关闭定时器,可以调用 removeCallbacks 方法
handler.removeCallbacks(runnable)
postDelayed 原理分析:
- 消息是通过 MessageQueue 中的 enqueueMessage 方法加入消息队列的,在放入就进行排序,链表头的延迟时间小,尾部延迟时间大。
- Looper.loop() 通过 MessageQueue 的 next() 去取消息。
- 如果当前链表头部消息是延迟消息,则根据延迟时间进行消息队列阻塞,不返回 Message,时间到了才返回。
- 如果在阻塞中有新的消息插入到链表头部则唤醒线程,Looper 将新消息回调给 Handler 中的 handleMessage 后,继续调用 MessageQueen 的 next(),如果刚刚的延迟消息还是时间未到,则计算时间继续阻塞。
postDelayed 和 sendMessage 的区别
其实,postDelayed 和 sendMessage 本质上没啥区别,都是发送消息到 Handler 所在线程的消息队列中。
只是代码实现上有些区别,postDelayed 方法会在消息入队之前封装成一个 Message,Runnable 放到了 message.callback 中,然后发送 message,处理消息的时候,检查 mCallback 是否为 Null,不为 Null 就调用 mCallback 的 handleMessage 方法来处理消息。
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
view.post 内部是获取到 View 所在线程(即 UI 线程)的 Handler,调用了 Handler 的 post 方法