47人参与 • 2025-10-20 • Android
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() 只能调用一次,否则抛出 runtimeexceptionlooper.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 保证每个线程独享一个 looperloop() 是死循环,通过 queue.next() 阻塞等待消息msg.target 即发送该消息的 handlerboolean 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;
}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;
}
}
}// 如 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 消息机制。
到此这篇关于android handler 机制原理详解的文章就介绍到这了,更多相关android handler 机制内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论