Android Handler 机制详解
Handler 是 Android 系统中用于线程间通信的核心机制,它构成了 Android 消息系统的基础。理解 Handler 机制对于开发流畅、高效的 Android 应用至关重要。
Handler 机制的核心组件
Android 的 Handler 机制主要由以下四个核心类组成:
- Handler - 消息的发送者和处理者
- Message - 消息的载体
- MessageQueue - 消息队列,存储待处理的消息
- Looper - 消息循环器,负责从 MessageQueue 中取出消息并分发
各组件详解
1. Message(消息)
Message 是线程间通信的数据载体,包含以下重要字段:
1
2
3
4
5
6
7
| public int what; // 消息标识
public int arg1; // 整型参数1
public int arg2; // 整型参数2
public Object obj; // 任意对象
public long when; // 消息处理时间
Handler target; // 目标Handler
Runnable callback; // Runnable回调
|
获取 Message 实例的最佳实践:
1
2
3
4
| // 推荐使用obtain()而不是直接new,因为会从消息池中复用
Message msg = Message.obtain();
msg.what = 1;
msg.obj = "Hello";
|
2. MessageQueue(消息队列)
- 单链表结构实现的优先级队列,按消息处理时间(when)排序
- 每个线程最多只有一个 MessageQueue
- 主要操作:enqueueMessage() 和 next()
3. Looper(循环器)
Looper 的核心作用是不停地从 MessageQueue 中取出消息并分发:
1
2
3
4
5
6
7
8
9
10
11
12
13
| public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // 可能阻塞
if (msg == null) {
return;
}
msg.target.dispatchMessage(msg); // 分发消息
msg.recycleUnchecked(); // 回收消息
}
}
|
重要方法:
prepare()
: 初始化当前线程的Looperloop()
: 开始消息循环quit()
/quitSafely()
: 退出Looper
4. Handler(处理器)
Handler 是开发者最直接接触的类,主要功能:
- 发送消息:sendMessage(), post(Runnable)
- 处理消息:handleMessage(), dispatchMessage()
消息处理优先级:
- 如果Message有callback(Runnable),则执行Runnable
- 如果Handler有全局Callback,则执行Callback
- 最后调用handleMessage()
Handler 机制工作原理
初始化:
- Looper.prepare() 创建Looper和MessageQueue
- Looper.loop() 启动消息循环
发送消息:
- Handler发送消息到MessageQueue
- 消息按when时间排序插入队列
处理消息:
- Looper不断从队列取消息
- 将消息分发给目标Handler处理
- 处理完成后回收消息
线程(Thread)、循环器(Looper)、处理者(Handler)之间的对应关系如下:
- 1个线程(Thread)只能绑定 1个循环器(Looper),但可以有多个处理者(Handler)
- 1个循环器(Looper) 可绑定多个处理者(Handler)
- 1个处理者(Handler) 只能绑定1个循环器(Looper)
主线程消息循环
Android 主线程(UI线程)的消息循环是在ActivityThread中初始化的:
1
2
3
4
5
6
| public static void main(String[] args) {
Looper.prepareMainLooper(); // 初始化主线程Looper
ActivityThread thread = new ActivityThread();
thread.attach(false);
Looper.loop(); // 开始消息循环
}
|
Handler 的使用场景
1. 线程间通信(子线程→主线程)
1
2
3
4
5
6
7
8
9
10
11
12
13
| // 在主线程创建Handler
Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
// 在主线程处理消息
}
};
// 在子线程发送消息
new Thread(() -> {
Message msg = handler.obtainMessage(1, "Data");
handler.sendMessage(msg);
}).start();
|
2. 延迟任务
1
2
3
4
5
6
7
| // 延迟1秒执行
handler.postDelayed(() -> {
// 执行任务
}, 1000);
// 取消延迟任务
handler.removeCallbacks(runnable);
|
3. 定时任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| private static final int MSG_UPDATE = 1;
private static final long INTERVAL = 1000; // 1秒
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_UPDATE) {
// 执行任务
sendEmptyMessageDelayed(MSG_UPDATE, INTERVAL);
}
}
};
// 开始定时任务
handler.sendEmptyMessage(MSG_UPDATE);
// 停止定时任务
handler.removeMessages(MSG_UPDATE);
|
4.线程间通讯(主线程→子线程)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // 子线程代码
Thread workerThread = new Thread(() -> {
Looper.prepare(); // 初始化Looper
Handler workerHandler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
// 处理主线程发来的消息
Log.d("WorkerThread", "收到消息: " + msg.what);
}
};
Looper.loop(); // 启动消息循环
});
workerThread.start();
// 主线程代码(如Activity中)
Handler mainHandler = new Handler(workerThread.getLooper()); // 需确保workerThread已启动
mainHandler.sendEmptyMessage(1); // 发送消息
|
或者
1
2
3
4
5
6
7
8
| // 创建一个带有 Looper 的子线程
HandlerThread workerThread = new HandlerThread("MyHandlerThread");
handlerThread.start(); // 必须调用 start() 来启动线程和 Looper
// 主线程代码(如Activity中)
Handler mainHandler = new Handler(workerThread.getLooper()); // 需确保workerThread已启动
mainHandler.sendEmptyMessage(1); // 发送消息
|
Handler 内存泄漏问题
常见场景:
1
2
3
4
5
6
7
8
| public class MainActivity extends Activity {
private final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 处理消息
}
};
}
|
问题原因:
- Handler 持有 Activity 的隐式引用(匿名内部类)
- Message 持有 Handler 引用
- Message 可能长时间存在于 MessageQueue 中
- 导致 Activity 无法被回收
解决方案:
- 使用静态内部类 + WeakReference:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| private static class SafeHandler extends Handler {
private final WeakReference<MainActivity> activityRef;
public SafeHandler(MainActivity activity) {
activityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = activityRef.get();
if (activity != null) {
// 处理消息
}
}
}
|
- 在 Activity 销毁时移除所有消息:
1
2
3
4
5
| @Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}
|
HandlerThread
HandlerThread 是 Android 提供的便捷类,集成了 Thread + Looper:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // 创建HandlerThread
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
// 创建关联该Looper的Handler
Handler handler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
// 在handlerThread线程处理消息
}
};
// 退出时清理
handlerThread.quitSafely();
|
同步屏障机制(Sync Barrier)
同步屏障是 Handler 的高级特性,用于优先处理异步消息:
1
2
3
4
5
6
7
8
9
10
11
12
13
| // 插入同步屏障(API 23+)
MessageQueue queue = Looper.getMainLooper().getQueue();
Method method = MessageQueue.class.getDeclaredMethod("postSyncBarrier");
int token = (int) method.invoke(queue);
// 发送异步消息
Message msg = Message.obtain();
msg.setAsynchronous(true);
handler.sendMessage(msg);
// 移除同步屏障
Method removeMethod = MessageQueue.class.getDeclaredMethod("removeSyncBarrier", int.class);
removeMethod.invoke(queue, token);
|
应用场景:Choreographer 中用于优先处理垂直同步信号
性能优化建议
- 避免频繁创建 Message:使用 Message.obtain() 复用消息
- 及时清理消息:在不需要时调用 removeCallbacksAndMessages(null)
- 合理使用延迟消息:避免大量延迟消息堆积
- 谨慎使用同步屏障:不当使用可能导致UI卡顿
- 考虑使用 IdleHandler:在消息队列空闲时执行任务
1
2
3
4
| Looper.myQueue().addIdleHandler(() -> {
// 空闲时执行
return false; // true表示保持,false表示移除
});
|
Handler 机制与协程对比
特性 | Handler | Kotlin 协程 |
---|
线程模型 | 显式指定Handler/Looper | 通过Dispatchers指定上下文 |
内存泄漏风险 | 需要手动处理 | 通过CoroutineScope自动管理 |
代码可读性 | 回调嵌套,可读性差 | 顺序编写,可读性好 |
取消操作 | 需要手动remove | 通过Job自动取消 |
适用场景 | 简单线程切换、延迟任务 | 复杂异步流程、并发任务 |
在现代 Android 开发中,对于复杂异步逻辑推荐使用协程,但 Handler 仍然是系统底层的基础机制,理解其原理对于解决深层次问题非常有帮助。