
@TOC
Handler 机制是 Android 系统中实现**线程间通信(Inter-thread Communication)**的核心机制,尤其广泛用于将子线程中的任务结果传递回主线程(UI线程)进行更新操作。其底层基于 **消息队列(MessageQueue)** 和 **循环器(Looper)** 构建,形成一个典型的生产者-消费者模型。
该机制的核心目标是:
Handler 是开发者最常接触的类,负责:
sendMessage()、post() 等方法handleMessage(Message msg) 或设置 CallbackLooper 和 MessageQueue 绑定每个
Handler必须关联一个Looper,否则会抛出异常。
// 示例:创建 Handler 并绑定当前线程的 Looper
Handler handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
// 在指定线程中处理消息
}
};MessageQueue 是一个按时间排序的消息队列,内部使用**单向链表**结构存储待处理的消息。
主要职责:
Handler 发送的 MessageMessage.when(执行时间戳)排序插入next() 方法供 Looper 取出下一条可执行消息
MessageQueue并非传统 FIFO 队列,而是根据执行时间排序的优先队列。
Looper 是消息循环的驱动者,每个线程最多只能有一个 Looper。
关键功能:
Looper.prepare() 初始化当前线程的 LooperLooper.loop() 启动无限循环,不断从 MessageQueue 取出消息并分发ThreadLocal 保证线程局部性// 主线程中系统自动调用
Looper.prepareMainLooper(); // 初始化主线程 Looper
...
Looper.loop(); // 开始循环Message 是消息的载体,包含以下核心字段:
| 字段 | 说明 |
|------|------|
| what | 用户自定义消息类型 |
| arg1, arg2 | 整型参数,用于传递简单数据 |
| obj | 任意对象(注意内存泄漏风险) |
| target | 目标 Handler,由 Handler.sendMessage() 自动设置 |
| callback | 如果是 post(Runnable),则 Runnable 封装为 callback |
| when | 消息应被执行的时间戳(毫秒) |
| next | 指向链表中的下一个 Message |
推荐使用
Message.obtain()获取实例,避免频繁创建对象。

在非主线程中若要使用 Handler,必须手动创建 Looper。
class WorkerThread extends Thread {
public Handler handler;
@Override
public void run() {
Looper.prepare(); // 创建当前线程的 Looper 和 MessageQueue
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case 1:
Log.d("Handler", "收到消息: " + msg.obj);
break;
}
}
};
Looper.loop(); // 开始无限循环读取消息
}
public void quit() {
if (handler != null) {
handler.getLooper().quit(); // 安全退出循环
}
}
}📌 注意:
Looper.prepare()只能调用一次,否则抛出RuntimeException
Looper.loop()是阻塞方法,直到调用quit()才退出
Handler 提供多种发送消息的方式:
| 方法 | 说明 |
|------|------|
| sendEmptyMessage(int what) | 发送空消息 |
| sendMessage(Message msg) | 发送自定义消息 |
| post(Runnable r) | 发送 Runnable 任务 |
| sendEmptyMessageDelayed(what, delay) | 延迟发送 |
| postDelayed(Runnable r, long delayMillis) | 延迟执行 Runnable |
底层均调用 enqueueMessage() 将消息插入 MessageQueue。
// 示例:多种发送方式
handler.sendEmptyMessage(1);
Message msg = Message.obtain();
msg.what = 2;
msg.obj = "Hello";
handler.sendMessage(msg);
handler.post(() -> {
Log.d("Handler", "Runnable 执行");
});
handler.postDelayed(() -> {
Log.d("Handler", "1秒后执行");
}, 1000);Handler.dispatchMessage() 是消息分发的核心逻辑:
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
// 优先处理 post(Runnable) 类型的消息
handleCallback(msg);
} else {
if (mCallback != null) {
// 其次交给 Handler 的 Callback 处理
if (mCallback.handleMessage(msg)) {
return;
}
}
// 最终调用 handleMessage
handleMessage(msg);
}
}
private void handleCallback(Message message) {
message.callback.run(); // 直接执行 Runnable
}执行顺序:
Runnable>Callback>handleMessage
public final class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
final MessageQueue mQueue;
final Thread mThread;
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
// 准备 Looper
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
// 获取当前线程的 Looper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
// 消息循环主方法
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // 可能阻塞
if (msg == null) return; // 退出循环
// 分发消息
try {
msg.target.dispatchMessage(msg);
} finally {
// 空实现,预留钩子
}
msg.recycleUnchecked(); // 回收消息
}
}
}🔍 关键点:
ThreadLocal保证每个线程独享一个Looper
loop()是死循环,通过queue.next()阻塞等待消息
msg.target即发送该消息的Handler
enqueueMessage() —— 入队boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
final long now = SystemClock.uptimeMillis();
msg.when = when;
Message p = mMessages; // 链表头节点
if (p == null || when == 0 || when < p.when) {
// 插入头部
msg.next = p;
mMessages = msg;
} else {
// 按时间顺序插入中间
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
}
msg.next = p;
prev.next = msg;
}
// 唤醒消息队列(如果之前处于等待状态)
notify();
}
return true;
}next() —— 出队(核心阻塞方法)Message next() {
final long ptr = mPtr;
if (ptr == 0) return null; // 已退出
long pendingIdleHandlerCount = -1;
long nextPollTimeoutMillis = 0;
for (;;) {
// 阻塞等待,timeout 为 0 表示无限等待
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
// 同步屏障处理:跳过同步消息,只处理异步消息
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// 未到执行时间,计算等待时间
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX\_VALUE);
} else {
// 可执行,取出消息
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
msg.markInUse();
return msg;
}
} else {
// 无消息,无限等待
nextPollTimeoutMillis = -1;
}
// 处理 IdleHandler(空闲时执行)
if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount > 0) {
// 执行空闲任务
}
}
}
}用于优先处理异步消息(如 UI 绘制),屏蔽同步消息。
应用场景:
ViewRootImpl 请求重绘时插入屏障,确保 Choreographer 的 VSYNC 消息优先执行// 插入同步屏障
int token = mHandler.getLooper().getQueue().postSyncBarrier();
// 移除屏障
mHandler.getLooper().getQueue().removeSyncBarrier(token);⚠️ 滥用可能导致同步消息饥饿,不建议普通应用使用。
当 MessageQueue 没有消息需要处理时,会回调 IdleHandler,可用于执行低优先级任务。
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
Log.d("IdleHandler", "消息队列空闲,执行预加载");
// 返回 true:保持注册;false:执行一次后移除
return false;
}
});典型用途:
避免被同步屏障阻塞,适用于高优先级任务。
Message msg = Message.obtain(handler, runnable);
msg.setAsynchronous(true);
handler.sendMessageAtTime(msg, SystemClock.uptimeMillis() + 1000);
Handler.createAsync()可创建专门处理异步消息的Handler
为减少频繁创建/销毁对象带来的 GC 压力,Message 内部维护了一个对象池。
public final class Message implements Parcelable {
private static final int MAX\_POOL\_SIZE = 50;
private static Message sPool;
private static int sPoolSize = 0;
private static final Object sPoolSync = new Object();
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0;
sPoolSize--;
return m;
}
}
return new Message();
}
public void recycle() {
if (isInUse()) return;
recycleUnchecked();
}
void recycleUnchecked() {
flags = FLAG\_IN\_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
target = null;
callback = null;
data = null;
when = 0;
synchronized (sPoolSync) {
if (sPoolSize < MAX\_POOL\_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
}建议始终使用
Message.obtain()而非new Message()
常见场景:非静态内部类 Handler 持有外部 Activity 引用,导致无法回收。
private static class SafeHandler extends Handler {
private final WeakReference<MainActivity> mActivity;
public SafeHandler(MainActivity activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(@NonNull Message msg) {
MainActivity activity = mActivity.get();
if (activity == null || activity.isFinishing() || activity.isDestroyed()) {
return;
}
switch (msg.what) {
case 1:
activity.updateUI((String) msg.obj);
break;
}
}
}WeakHandler(第三方库)// 如 Square 的 LeakCanary 推荐方式
WeakHandler weakHandler = new WeakHandler(this, new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
// 安全处理
return true;
}
});在子线程中使用 Looper 后,应在适当时机退出,避免资源浪费。
// 安全退出:处理完已到时的消息再退出
handler.getLooper().quitSafely();
// 立即退出:丢弃所有未处理消息
handler.getLooper().quit();建议在
Thread的onDestroy或quit()方法中调用
| 线程类型 | Looper 是否自动创建 | 使用方式 |
|--------|---------------------|---------|
| 主线程(UI线程) | 是(系统自动调用 Looper.prepareMainLooper()) | 直接创建 Handler |
| 子线程 | 否 | 必须手动调用 Looper.prepare() 和 Looper.loop() |
| 问题 | 解决方案 |
|------|----------|
| Can't create handler inside thread that has not called Looper.prepare() | 在子线程中先调用 Looper.prepare() |
| 内存泄漏 | 使用静态 Handler + WeakReference |
| 消息延迟不准 | 系统休眠或高负载可能导致延迟,不保证精确时间 |
| 大量消息堆积 | 控制消息频率,避免 OOM |
| 使用 postDelayed 实现轮询 | 不推荐,应使用 AlarmManager 或 WorkManager 替代 |
Android 的 Handler 机制是一个精巧的线程通信架构,其设计体现了以下几个关键思想:
| 组件 | 角色 | 设计亮点 |
|------|------|-----------|
| Handler | 消息生产者与消费者 | 提供易用的 API |
| MessageQueue | 消息存储与调度 | 单链表 + 时间排序 + 阻塞唤醒机制 |
| Looper | 消息循环驱动 | ThreadLocal + 无限循环 |
| Message | 消息载体 | 对象池复用 + 多种数据承载方式 |
Message 对象池减少 GC 压力removeCallbacks 防止泄漏)💡 尽管现代 Android 开发越来越多地使用
Coroutine、LiveData、RxJava等替代方案,但Handler仍是底层基石,理解其原理有助于深入掌握 Android 消息机制。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。