Handler 是 Android 中实现线程间通信的核心类,主要用于在不同线程(如主线程与子线程)之间发送和处理消息。它是 Android 消息机制的核心组件,理解其原理对开发高性能应用至关重要。
一、核心组件与协作关系
Handler
作用:发送消息 (sendMessage) 和处理消息 (handleMessage)。
绑定关系:每个 Handler 必须关联一个线程的 Looper(默认绑定当前线程的 Looper)。
Looper
作用:循环从 MessageQueue 中取出消息,分发给对应的 Handler 处理。
关键方法:
Looper.prepare():初始化当前线程的 Looper。
Looper.loop():启动消息循环。
主线程 Looper:由系统自动创建,开发者无需手动调用 prepare()。
MessageQueue
作用:存储待处理的消息(单链表结构,按时间排序)。
线程唯一性:每个线程最多一个 MessageQueue,由 Looper 管理。
Message
作用:消息的载体,包含 what(标识)、arg1/arg2(简单数据)、obj(复杂对象)等字段。
优化建议:使用 Message.obtain() 复用消息对象,避免内存抖动。
二、工作原理流程图
+----------------+ +----------------+ +-------------------+
| Handler | ----> | MessageQueue | <---- | Looper |
| (sendMessage) | | (enqueueMessage)| | (loop() 轮询取消息) |
+----------------+ +-------------------+ +-------------------+
↑ |
| ↓
+----------------+ +-------------------+
| 子线程/主线程 | | Handler |
| (触发消息发送) | | (handleMessage()) |
+----------------+ +-------------------+
发送消息:Handler 通过 sendMessage() 或 post(Runnable) 将消息插入 MessageQueue。
轮询消息:Looper 不断调用 MessageQueue.next() 取出下一条消息(若无消息则阻塞)。
分发处理:Looper 将消息分发给目标 Handler,执行其 handleMessage() 或 Runnable。
三、关键代码示例
// 主线程中创建 Handler(自动关联主线程 Looper)
Handler mainHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
// 处理主线程消息(如更新 UI)
}
};
// 子线程中使用 Handler
new Thread(() -> {
Looper.prepare(); // 初始化子线程 Looper
Handler threadHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 处理子线程消息
}
};
Looper.loop(); // 启动消息循环
}).start();
// 发送消息示例
mainHandler.sendEmptyMessage(1); // 发送空消息
mainHandler.post(() -> { /* 执行 Runnable */ }); // 发送 Runnable
四、使用场景与最佳实践
主线程更新 UI
子线程处理完耗时任务后,通过 Handler 通知主线程更新 UI。
new Thread(() -> {
// 子线程执行耗时操作
String result = fetchDataFromNetwork();
mainHandler.post(() -> textView.setText(result)); // 切回主线程更新 UI
}).start();
定时任务与延迟执行
使用 postDelayed() 实现定时操作(如轮询、动画)。
handler.postDelayed(() -> {
// 延迟 1 秒执行
}, 1000);
跨线程通信
多个线程通过 Handler 共享数据或协调任务。
避免内存泄漏
问题:非静态内部类 Handler 隐式持有外部类(如 Activity)引用,若 Activity 销毁时仍有未处理消息,会导致内存泄漏。
解决方案:
使用静态内部类 + WeakReference。
在 onDestroy() 中调用 handler.removeCallbacksAndMessages(null) 移除所有消息。
五、常见问题与解决
子线程中创建 Handler 崩溃
错误日志:Can't create handler inside thread that has not called Looper.prepare()
原因:子线程未初始化 Looper。
解决:调用 Looper.prepare() 和 Looper.loop()。
主线程 Looper 的初始化时机
答案:在应用启动时,系统通过 ActivityThread.main() 调用 Looper.prepareMainLooper() 初始化主线程 Looper。
消息同步屏障(Sync Barrier)
作用:优先处理异步消息(如 UI 绘制消息 VSYNC),通过 postSyncBarrier() 插入屏障。
应用场景:确保高优先级消息及时处理。
HandlerThread 的使用
定位:自带 Looper 的子线程,简化 Handler 在子线程中的使用。
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
六、与其他异步机制的对比
| 机制 | 特点 | 适用场景 |
|---|---|---|
| Handler | 灵活、底层,需手动管理消息队列和线程切换 | 跨线程通信、定时任务、UI 更新 |
| AsyncTask | 封装简化,但易内存泄漏,已废弃 | 简单后台任务(不推荐新项目使用) |
| RxJava | 响应式编程,链式调用,强大的线程切换和错误处理 | 复杂异步流、事件组合 |
| Coroutines | 轻量级协程,结构化并发,代码简洁 | 现代 Android 开发的首选异步方案 |
七、总结
核心角色:Handler 是 Android 消息机制的枢纽,负责跨线程通信和任务调度。
关键点:理解 Looper、MessageQueue 的协作,避免内存泄漏,合理选择异步方案。
演进:随着 Kotlin 协程的普及,直接使用 Handler 的场景减少,但其底层原理仍至关重要(如协程的 Dispatchers.Main 内部依赖 Handler)。