Android Handler
面试可先答:四件套 Message、MessageQueue、Looper、Handler;线程切换本质是多线程共享同一 MessageQueue,通过 Handler 投递、Looper 分发;子线程需 Looper.prepare() + loop();注意内存泄漏与 removeCallbacksAndMessages。详见笔记《Android 面试·分章系统复习》第七章 Handler 机制。
阅读建议:先看 应用场景 与 四件套,再 线程切换本质、ThreadLocal、同步屏障,最后 HandlerThread 案例 与 常见问题。
应用场景
Android 更新 UI 必须在主线程执行。Handler 用于在不同线程之间传递消息,把「更新 UI」等任务投递到主线程执行。
核心模块与架构(四件套)
| 组件 | 作用 |
|---|---|
| Message | 消息载体,含 what、obj、target(归属 Handler)、when(执行时间) |
| MessageQueue | 按时间顺序排列的优先级单链表 |
| Looper | 线程内的死循环,从 MessageQueue 取消息并分发 |
| Handler | 发送消息入队,并接收 Looper 回传的消息在对应线程处理 |
架构示意:

线程切换的本质:数据如何跨越线程?
结论:多线程共享同一个 MessageQueue 对象,通过 Handler 引用实现跨线程投递。
- 绑定引用:Handler 创建时绑定一个 Looper(及该 Looper 唯一的 MessageQueue)。
- 跨线程入队:任意线程调用
handler.sendMessage(),底层都是操作该 Handler 持有的mQueue。 - 同步:
MessageQueue.enqueueMessage内用 synchronized(this) 保证线程安全。 - 唤醒执行:消息入队后,通过 Linux epoll 唤醒正在阻塞的线程,由该线程的 Looper 取消息并执行。
线程隔离:ThreadLocal
- 问题:Handler 如何保证绑定的 Looper 就是目标线程的?
- 原理:Looper 用 ThreadLocal 存储,每个线程一份独立副本,保证「一个线程只有一个 Looper」,实现线程间资源隔离。
进阶:同步屏障(Sync Barrier)
- 定义:
target == null的特殊消息。 - 作用:屏障后的普通消息被挂起,只允许异步消息通过。
- 场景:Choreographer 收到 VSYNC 时插入同步屏障,让 UI 绘制(异步消息)优先执行,保证流畅。
- 注意:屏障须用 token 手动移除,否则普通消息会一直被阻塞。
实战:HandlerThread
子线程使用 Handler 的标准写法:
// 1. 创建带 Looper 的后台线程(内部已 prepare + loop)
HandlerThread handlerThread = new HandlerThread("BackgroundThread");
handlerThread.start();
// 2. 绑定子线程 Looper(主线程 new Handler 也可,消息会发到子线程)
Handler backgroundHandler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
// 运行在 BackgroundThread
}
};
// 3. 跨线程发送
backgroundHandler.sendMessage(Message.obtain());
常见问题与避坑
(1) 内存泄漏
- 原因:非静态内部类 Handler 隐式持有 Activity;Message 持有 Handler → Message → Handler → Activity,消息未处理完时 Activity 无法回收。
- 做法:① 静态内部类 +
WeakReference<Activity>,handleMessage里get()判空;②onDestroy()里handler.removeCallbacksAndMessages(null)。
(2) Looper.loop() 为何不卡死主线程?
- 无消息时
queue.next()在 native 层通过 epoll 阻塞,不占 CPU;有消息时被唤醒。 - 真正卡死/ANR 是某条消息在
handleMessage里做了耗时操作,导致后续消息(含绘制)得不到执行。
(3) 子线程创建 Handler
必须先:Looper.prepare() → new Handler() → Looper.loop();或直接使用 HandlerThread。
一句话总结
Handler 机制通过 ThreadLocal 保证每线程唯一的 Looper 和 MessageQueue,用 Handler 作为媒介,实现多线程向同一队列投递消息,由目标线程的 Looper 循环分发。
参考:语雀原文 Handler