Handler使用方式
📌 面试重要度:⭐⭐⭐⭐⭐
考察频率:字节 95% | 阿里 90% | 腾讯 92%
一、核心概念
1.1 定义与作用
一句话定义: Handler 使用方式是指通过 Handler 提供的各种 API(sendMessage、post、postDelayed 等)发送和处理消息的不同方法,以实现线程间通信、延迟执行、定时任务等功能。
为什么重要:
- 实战核心:Handler 是 Android 开发中最常用的线程通信工具,每个项目几乎都会用到
- 面试高频:面试官必问 Handler 的使用方式、各 API 区别、最佳实践
- 易错点多:内存泄漏、ANR、线程安全等常见问题都与 Handler 使用不当有关
- API 丰富:sendMessage、post、postDelayed、postAtTime 等 10+ API,需要掌握各自特点
1.2 与其他概念的关系
Handler 使用方式建立在 Handler 四大核心类(Handler、Message、MessageQueue、Looper)基础之上(详见 ./01-Handler基本概念.md),具体执行流程由消息队列调度完成(详见 ./03-Handler工作流程.md)。本文聚焦于实际开发中如何使用 Handler 的各种 API。
二、核心原理
2.1 Handler 创建方式
方式1:无参构造(已废弃)
// Android 11+ 已标记为 @Deprecated
Handler handler = new Handler();
废弃原因: Android 11(API 30)开始废弃无参构造,强制开发者明确指定 Looper 或 Callback,避免隐式绑定当前线程 Looper 导致的不确定性。
源码依据:
// frameworks/base/core/java/android/os/Handler.java (Android 12)
/**
* @deprecated Implicitly choosing a Looper during Handler construction can lead to bugs
* where operations are silently lost (if the Handler is not expecting new tasks and quits),
* crashes (if a handler is sometimes created on a thread without a Looper active), or race
* conditions, where the thread a handler is associated with is not what the author anticipated.
* Instead, use an Executor or specify the Looper explicitly, using Looper#getMainLooper, etc.
*/
@Deprecated
public Handler() {
this(null, false);
}
方式2:指定 Looper(推荐)
// 创建主线程 Handler
Handler mainHandler = new Handler(Looper.getMainLooper());
// 创建子线程 Handler
HandlerThread thread = new HandlerThread("WorkThread");
thread.start();
Handler workHandler = new Handler(thread.getLooper());
特点:
- 明确指定 Handler 绑定的线程
- 避免隐式依赖当前线程 Looper
- 推荐使用方式
源码实现:
// frameworks/base/core/java/android/os/Handler.java (Android 12)
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
this(looper, callback, false);
}
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
方式3:使用 Callback 接口
Handler handler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
// 处理消息
return true; // 返回 true 拦截,不再调用 Handler.handleMessage()
}
});
特点:
- 避免创建子类,代码更简洁
- 可通过返回值控制消息分发链
- 适合一次性使用场景
方式4:继承 Handler 子类(传统方式)
private static class MyHandler extends Handler {
private final WeakReference<Activity> mActivityRef;
public MyHandler(Activity activity) {
super(Looper.getMainLooper());
mActivityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(@NonNull Message msg) {
Activity activity = mActivityRef.get();
if (activity != null) {
// 处理消息
}
}
}
特点:
- 适合复杂消息处理逻辑
- 必须使用静态内部类 + 弱引用,避免内存泄漏
- 代码稍冗余,但结构清晰
2.2 消息发送方式
Handler 提供了两大类消息发送 API:Message 系列和 Runnable 系列。
2.2.1 Message 系列 API
完整 API 列表:
| API | 作用 | 执行时机 |
|---|---|---|
sendMessage(Message) | 发送消息 | 立即插入队列,按队列顺序执行 |
sendEmptyMessage(int what) | 发送空消息 | 立即插入队列 |
sendMessageDelayed(Message, long) | 延迟发送 | 延迟指定毫秒后执行 |
sendMessageAtTime(Message, long) | 指定时间发送 | 在指定绝对时间执行 |
sendMessageAtFrontOfQueue(Message) | 插入队列头部 | 优先执行(慎用) |
核心方法源码分析:
// frameworks/base/core/java/android/os/Handler.java (Android 12)
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what) {
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this; // ← 关键:设置消息的目标 Handler
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); // ← 插入消息队列
}
关键设计:
- 统一入口:所有 sendMessage 最终调用
sendMessageAtTime() - 时间计算:delay 使用相对时间,内部转换为绝对时间(uptimeMillis)
- target 绑定:在
enqueueMessage()中设置msg.target = this,确保消息回到正确的 Handler
使用示例:
// 示例1:发送普通消息
Message msg = Message.obtain();
msg.what = MSG_UPDATE_UI;
msg.arg1 = 100;
msg.obj = "data";
handler.sendMessage(msg);
// 示例2:发送空消息
handler.sendEmptyMessage(MSG_REFRESH);
// 示例3:延迟发送
handler.sendMessageDelayed(msg, 3000); // 3秒后执行
// 示例4:指定绝对时间
long triggerTime = SystemClock.uptimeMillis() + 5000;
handler.sendMessageAtTime(msg, triggerTime);
2.2.2 Runnable 系列 API
完整 API 列表:
| API | 作用 | 底层实现 |
|---|---|---|
post(Runnable) | 发送 Runnable | 包装为 Message.callback |
postDelayed(Runnable, long) | 延迟发送 | 包装为 Message.callback |
postAtTime(Runnable, long) | 指定时间发送 | 包装为 Message.callback |
postAtFrontOfQueue(Runnable) | 插入队列头部 | 优先执行(慎用) |
核心方法源码分析:
// frameworks/base/core/java/android/os/Handler.java (Android 12)
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
// 关键方法:Runnable 转 Message
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r; // ← 核心:将 Runnable 赋值给 Message.callback
return m;
}
关键设计:
- 统一底层:post 系列本质是 sendMessage,只是将 Runnable 包装为
Message.callback - 优先级最高:在消息分发时,
msg.callback优先于Handler.handleMessage()执行(详见./01-Handler基本概念.md的三级分发机制)
使用示例:
// 示例1:post 简单任务
handler.post(() -> {
textView.setText("更新 UI");
});
// 示例2:postDelayed 延迟任务
handler.postDelayed(() -> {
Toast.makeText(context, "3秒后显示", Toast.LENGTH_SHORT).show();
}, 3000);
// 示例3:postAtTime 定时任务
long targetTime = SystemClock.uptimeMillis() + 10000;
handler.postAtTime(() -> {
// 10秒后执行
}, targetTime);
2.2.3 Message vs Runnable 选择
| 对比项 | sendMessage | post(Runnable) |
|---|---|---|
| 使用场景 | 需要传递数据、复用 Message 对象 | 简单任务、无需传递复杂数据 |
| 代码简洁度 | 需要创建 Message、处理 what | 一行代码完成 |
| 性能 | 可复用 Message 对象池 | 每次创建新 Message |
| 灵活性 | 支持 what/arg1/arg2/obj/data | 只能执行 Runnable.run() |
| 消息管理 | 可通过 what 移除特定消息 | 只能通过 Runnable 引用移除 |
推荐原则:
- ✅ 使用 sendMessage:需要传递多个参数、需要复用消息、需要精确移除消息
- ✅ 使用 post:简单 UI 更新、一次性任务、代码简洁优先
2.3 消息移除方式
完整 API 列表:
| API | 作用 | 使用场景 |
|---|---|---|
removeMessages(int what) | 移除指定 what 的所有消息 | 取消特定类型消息 |
removeMessages(int what, Object object) | 移除指定 what 和 obj 的消息 | 精确移除 |
removeCallbacks(Runnable r) | 移除指定 Runnable | 取消 post 的任务 |
removeCallbacksAndMessages(null) | 移除所有消息 | Activity 销毁时清理 |
源码实现:
// frameworks/base/core/java/android/os/Handler.java (Android 12)
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
public final void removeMessages(int what, @Nullable Object object) {
mQueue.removeMessages(this, what, object);
}
public final void removeCallbacks(@NonNull Runnable r) {
mQueue.removeMessages(this, r, null);
}
public final void removeCallbacksAndMessages(@Nullable Object token) {
mQueue.removeCallbacksAndMessages(this, token);
}
关键实现(MessageQueue):
// frameworks/base/core/java/android/os/MessageQueue.java (Android 12)
void removeMessages(Handler h, int what, Object object) {
synchronized (this) {
Message p = mMessages;
// 移除链表头部匹配的消息
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// 移除链表中间匹配的消息
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
使用示例:
// 示例1:移除特定 what 的消息
handler.removeMessages(MSG_UPDATE);
// 示例2:移除特定 what 和 obj 的消息
handler.removeMessages(MSG_REFRESH, dataObject);
// 示例3:移除 Runnable
Runnable task = () -> { /* ... */ };
handler.post(task);
handler.removeCallbacks(task); // 取消任务
// 示例4:移除所有消息(Activity 销毁时)
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}
2.4 重要细节与边界条件
细节1:SystemClock.uptimeMillis() vs System.currentTimeMillis()
// Handler 内部使用 uptimeMillis
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
// uptimeMillis = SystemClock.uptimeMillis() + delay
}
区别:
| 时间类型 | 说明 | 是否受系统时间影响 |
|---|---|---|
SystemClock.uptimeMillis() | 系统启动到现在的时间(不含深度睡眠) | ❌ 否 |
System.currentTimeMillis() | 当前时间戳(1970至今) | ✅ 是(用户修改系统时间会影响) |
为什么使用 uptimeMillis:
- 避免用户修改系统时间导致延迟任务失效
- 设备休眠时不会计时,更符合"活跃时间"语义
细节2:sendMessageAtFrontOfQueue 的危险性
public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
MessageQueue queue = mQueue;
if (queue == null) {
return false;
}
return enqueueMessage(queue, msg, 0); // when = 0,插入队列头
}
危险原因:
- 打破顺序:破坏消息队列的时间顺序
- 可能饿死:频繁插队会导致其他消息长期得不到执行
- 难以调试:消息执行顺序不可预测
正确使用场景:
- 系统内部使用(如 ViewRootImpl 刷新请求)
- 紧急消息处理(如崩溃前的清理工作)
替代方案:
// 不推荐
handler.sendMessageAtFrontOfQueue(msg);
// 推荐:使用即时消息
handler.sendMessage(msg); // 立即插入队列,按顺序执行
细节3:Message 对象复用
// 错误示例
Message msg = new Message(); // ❌ 直接 new
// 正确示例
Message msg = Message.obtain(); // ✅ 从对象池获取
原因:
- Message 内部维护了最大容量 50 的对象池
- 使用
obtain()可避免频繁创建对象,减少 GC - 消息处理完毕后会自动调用
recycleUnchecked()放回池中
源码依据(详见 ./01-Handler基本概念.md):
// frameworks/base/core/java/android/os/Message.java (Android 12)
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();
}
三、实际应用
3.1 典型场景
场景1:子线程更新 UI
需求: 网络请求完成后,在主线程更新 UI。
使用方式:
public class NetworkActivity extends AppCompatActivity {
private TextView tvResult;
private Handler mainHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_network);
tvResult = findViewById(R.id.tv_result);
// 方式1:使用 Handler.Callback
mainHandler = new Handler(Looper.getMainLooper(), msg -> {
if (msg.what == 1) {
String result = (String) msg.obj;
tvResult.setText(result);
}
return true;
});
// 方式2:使用 post(更简洁)
mainHandler = new Handler(Looper.getMainLooper());
loadData();
}
private void loadData() {
new Thread(() -> {
// 模拟网络请求
try {
Thread.sleep(2000);
String data = "服务器返回数据";
// 方式1:sendMessage
Message msg = Message.obtain();
msg.what = 1;
msg.obj = data;
mainHandler.sendMessage(msg);
// 方式2:post(推荐)
mainHandler.post(() -> {
tvResult.setText(data);
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
mainHandler.removeCallbacksAndMessages(null);
}
}
注意事项:
- ✅ 使用
Looper.getMainLooper()确保 Handler 绑定主线程 - ✅
onDestroy()时移除所有消息,避免内存泄漏 - ✅ 简单 UI 更新优先使用
post(),代码更简洁
场景2:延迟任务(倒计时)
需求: 实现 60 秒倒计时,每秒更新 UI。
使用方式:
public class CountdownActivity extends AppCompatActivity {
private TextView tvCountdown;
private Handler handler;
private int countdown = 60;
private final Runnable countdownTask = new Runnable() {
@Override
public void run() {
if (countdown > 0) {
tvCountdown.setText(countdown + "秒");
countdown--;
handler.postDelayed(this, 1000); // 延迟1秒再次执行
} else {
tvCountdown.setText("倒计时结束");
// 可执行其他操作
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_countdown);
tvCountdown = findViewById(R.id.tv_countdown);
handler = new Handler(Looper.getMainLooper());
handler.post(countdownTask); // 开始倒计时
}
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacks(countdownTask); // 停止倒计时
}
}
注意事项:
- ✅ 使用
postDelayed()实现递归调用 - ✅ Runnable 定义为成员变量,方便
removeCallbacks() - ✅ 销毁时移除任务,避免内存泄漏
场景3:定时轮询
需求: 每隔 5 秒刷新数据,直到页面销毁。
使用方式:
public class PollingActivity extends AppCompatActivity {
private Handler handler;
private static final int MSG_POLL = 1;
private static final long POLL_INTERVAL = 5000; // 5秒
private final Handler.Callback callback = msg -> {
if (msg.what == MSG_POLL) {
refreshData();
// 继续轮询
handler.sendEmptyMessageDelayed(MSG_POLL, POLL_INTERVAL);
}
return true;
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_polling);
handler = new Handler(Looper.getMainLooper(), callback);
startPolling();
}
private void startPolling() {
handler.sendEmptyMessage(MSG_POLL); // 立即执行第一次
}
private void stopPolling() {
handler.removeMessages(MSG_POLL);
}
private void refreshData() {
// 刷新逻辑
Log.d("Polling", "刷新数据: " + System.currentTimeMillis());
}
@Override
protected void onDestroy() {
super.onDestroy();
stopPolling();
}
}
注意事项:
- ✅ 使用
sendEmptyMessageDelayed()实现定时轮询 - ✅ 提供
stopPolling()方法停止轮询 - ✅ 页面销毁时必须停止轮询
场景4:HandlerThread 使用
需求: 在子线程执行耗时任务,且需要消息队列管理任务顺序。
使用方式:
public class HandlerThreadExample {
private HandlerThread handlerThread;
private Handler workHandler;
public void start() {
// 创建 HandlerThread
handlerThread = new HandlerThread("WorkThread", Process.THREAD_PRIORITY_BACKGROUND);
handlerThread.start();
// 创建 Handler 绑定 HandlerThread 的 Looper
workHandler = new Handler(handlerThread.getLooper(), msg -> {
switch (msg.what) {
case 1:
processTask1(msg.obj);
break;
case 2:
processTask2(msg.obj);
break;
}
return true;
});
}
public void doWork(int type, Object data) {
Message msg = Message.obtain();
msg.what = type;
msg.obj = data;
workHandler.sendMessage(msg);
}
private void processTask1(Object data) {
// 耗时操作,在子线程执行
try {
Thread.sleep(1000);
Log.d("HandlerThread", "任务1完成: " + data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void processTask2(Object data) {
// 耗时操作,在子线程执行
Log.d("HandlerThread", "任务2完成: " + data);
}
public void stop() {
if (handlerThread != null) {
handlerThread.quitSafely();
try {
handlerThread.join(); // 等待线程结束
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
注意事项:
- ✅ 使用
quitSafely()安全退出(处理完已有消息再退出) - ✅ 可设置线程优先级(
Process.THREAD_PRIORITY_BACKGROUND) - ✅ 适合需要顺序执行的后台任务
3.2 最佳实践
✅ 推荐做法
1. 明确指定 Looper
// ✅ 推荐
Handler handler = new Handler(Looper.getMainLooper());
// ❌ 不推荐(Android 11+ 已废弃)
Handler handler = new Handler();
2. 使用静态内部类 + 弱引用
// ✅ 推荐
private static class SafeHandler extends Handler {
private final WeakReference<Activity> mActivityRef;
public SafeHandler(Activity activity) {
super(Looper.getMainLooper());
mActivityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(@NonNull Message msg) {
Activity activity = mActivityRef.get();
if (activity != null && !activity.isFinishing()) {
// 处理消息
}
}
}
// ❌ 不推荐(内存泄漏)
private Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
// 非静态内部类持有外部类引用
}
};
3. 优先使用 Message.obtain()
// ✅ 推荐
Message msg = Message.obtain();
msg.what = 1;
handler.sendMessage(msg);
// ❌ 不推荐
Message msg = new Message();
4. 及时移除消息
// ✅ 推荐
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}
// ❌ 不推荐(不清理,可能内存泄漏)
@Override
protected void onDestroy() {
super.onDestroy();
}
5. 简单任务使用 post()
// ✅ 推荐
handler.post(() -> textView.setText("更新"));
// ❌ 不推荐(过于繁琐)
Message msg = Message.obtain();
msg.what = 1;
msg.obj = "更新";
handler.sendMessage(msg);
❌ 常见错误
错误1:在子线程创建 Handler 忘记 Looper.prepare()
// ❌ 错误
new Thread(() -> {
Handler handler = new Handler(); // 崩溃:Can't create handler inside thread...
}).start();
// ✅ 正确
new Thread(() -> {
Looper.prepare();
Handler handler = new Handler();
Looper.loop();
}).start();
错误2:长时间持有 Activity 引用
// ❌ 错误
handler.postDelayed(() -> {
activity.findViewById(R.id.view); // activity 可能已销毁
}, 60000);
// ✅ 正确
handler.postDelayed(() -> {
if (!activity.isFinishing() && !activity.isDestroyed()) {
activity.findViewById(R.id.view);
}
}, 60000);
错误3:忘记移除 Runnable
// ❌ 错误
Runnable task = () -> { /* ... */ };
handler.postDelayed(task, 10000);
// Activity 销毁时未移除
// ✅ 正确
Runnable task = () -> { /* ... */ };
handler.postDelayed(task, 10000);
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacks(task);
}
错误4:使用 sendMessageAtFrontOfQueue 打乱顺序
// ❌ 错误
handler.sendMessageAtFrontOfQueue(msg); // 破坏消息顺序
// ✅ 正确
handler.sendMessage(msg); // 按时间顺序插入队列
3.3 性能优化建议
1. 避免频繁创建 Message
// ❌ 不推荐
for (int i = 0; i < 100; i++) {
Message msg = new Message();
handler.sendMessage(msg);
}
// ✅ 推荐
for (int i = 0; i < 100; i++) {
Message msg = Message.obtain();
handler.sendMessage(msg);
}
2. 合并多个消息
// ❌ 不推荐
handler.sendEmptyMessage(MSG_UPDATE_1);
handler.sendEmptyMessage(MSG_UPDATE_2);
handler.sendEmptyMessage(MSG_UPDATE_3);
// ✅ 推荐
handler.removeMessages(MSG_UPDATE); // 移除之前的更新
handler.sendEmptyMessage(MSG_UPDATE); // 只发送一次
3. 使用 HandlerThread 替代 Thread + Looper
// ❌ 不推荐
new Thread(() -> {
Looper.prepare();
handler = new Handler();
Looper.loop();
}).start();
// ✅ 推荐
HandlerThread thread = new HandlerThread("WorkThread");
thread.start();
handler = new Handler(thread.getLooper());
四、面试真题解析
4.1 基础必答题(P5必须掌握)
【高频题1】Handler 有哪些创建方式?推荐哪种?
标准答案(30秒): Handler 有四种创建方式:无参构造、指定 Looper、使用 Callback 接口、继承子类。无参构造在 Android 11 已废弃,推荐使用指定 Looper 的方式,如 new Handler(Looper.getMainLooper()),这样可以明确 Handler 绑定的线程,避免隐式依赖当前线程 Looper 导致的不确定性。对于简单场景可以使用 Callback 接口避免创建子类,对于复杂逻辑推荐使用静态内部类加弱引用避免内存泄漏。
深入展开(追问后):
为什么废弃无参构造? Android 11 废弃无参构造的原因是隐式绑定当前线程 Looper 容易导致三类问题:
- 静默丢失操作:在没有 Looper 的线程创建 Handler 会崩溃
- 竞态条件:Handler 关联的线程可能不是开发者预期的
- 代码可读性差:不明确 Handler 在哪个线程执行
源码中的警告信息明确说明了这一点:
// frameworks/base/core/java/android/os/Handler.java (Android 12)
/**
* @deprecated Implicitly choosing a Looper during Handler construction can lead to bugs
* where operations are silently lost (if the Handler is not expecting new tasks and quits),
* crashes (if a handler is sometimes created on a thread without a Looper active), or race
* conditions...
*/
@Deprecated
public Handler() {
this(null, false);
}
面试官追问:
追问1:如何在子线程创建 Handler?
答:子线程创建 Handler 需要三步:
new Thread(() -> {
Looper.prepare(); // 1. 创建 Looper
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 处理消息
}
};
Looper.loop(); // 2. 开启消息循环
}).start();
或者直接使用 HandlerThread:
HandlerThread thread = new HandlerThread("WorkThread");
thread.start();
Handler handler = new Handler(thread.getLooper());
追问2:Handler.Callback 返回 true 和 false 有什么区别?
答:
- 返回
true:拦截消息,不再调用Handler.handleMessage() - 返回
false:继续分发,会调用Handler.handleMessage()
这是责任链模式的应用,可以实现统一拦截处理:
Handler handler = new Handler(msg -> {
Log.d("Handler", "统一日志: " + msg.what);
return false; // 继续分发
}) {
@Override
public void handleMessage(Message msg) {
// 实际处理逻辑
}
};
【高频题2】sendMessage 和 post 有什么区别?
标准答案(30秒): sendMessage 和 post 的底层实现相同,都是调用 sendMessageAtTime 插入消息队列,区别在于使用方式和适用场景。sendMessage 需要创建 Message 对象,可以通过 what、arg1、arg2、obj 等字段传递多种数据,适合复杂消息处理;post 直接传入 Runnable,内部会将 Runnable 包装为 Message.callback,代码更简洁,适合简单的一次性任务。推荐简单 UI 更新用 post,需要传递数据或复用消息用 sendMessage。
深入展开(追问后):
源码验证:
// frameworks/base/core/java/android/os/Handler.java (Android 12)
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r; // ← 关键:Runnable 赋值给 callback
return m;
}
消息分发差异:
// frameworks/base/core/java/android/os/Handler.java (Android 12)
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg); // ← post 的 Runnable 在这里执行
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg); // ← sendMessage 在这里执行
}
}
面试官追问:
追问1:post 的 Runnable 在哪个线程执行?
答:Runnable 在 Handler 绑定的 Looper 所在线程执行。例如:
Handler mainHandler = new Handler(Looper.getMainLooper());
new Thread(() -> {
mainHandler.post(() -> {
// 这里在主线程执行,即使是子线程调用 post
textView.setText("更新 UI");
});
}).start();
追问2:能否多次 post 同一个 Runnable?
答:可以,每次 post 都会创建新的 Message 对象,将 Runnable 赋值给 msg.callback,因此同一个 Runnable 可以多次入队。但需要注意移除时必须使用 removeCallbacks(Runnable),会移除所有关联该 Runnable 的消息。
【高频题3】如何移除 Handler 的消息?
标准答案(30秒): Handler 提供了四种移除消息的方法:removeMessages 移除指定 what 的消息,removeCallbacks 移除指定 Runnable,removeCallbacksAndMessages(null) 移除所有消息。最常用的是 removeCallbacksAndMessages(null),通常在 Activity 的 onDestroy 中调用,移除所有待处理的消息,避免内存泄漏。移除消息时 Handler 会遍历 MessageQueue 链表,找到 target 等于当前 Handler 的消息并从链表中删除,同时调用 recycleUnchecked 回收 Message 对象。
深入展开(追问后):
核心原理:
MessageQueue.removeMessages() 遍历消息链表,移除匹配的消息:
- 头部匹配:循环移除链表头部匹配的消息
- 中间匹配:遍历链表,跳过并回收匹配的中间节点
- 消息回收:调用
recycleUnchecked()将消息放回对象池
详细源码实现:详见本文第 2.3 节"消息移除方式"
面试官追问:
追问1:removeCallbacksAndMessages(null) 为什么传 null?
答:参数 token 用于精确匹配 msg.obj,当传入 null 时,条件 object == null || p.obj == object 始终为 true,会移除所有 target == h 的消息,不限制 obj 字段。这是一种设计技巧,一个 API 实现两种功能:
- 传入 null:移除所有消息
- 传入具体对象:只移除 obj 匹配的消息
追问2:移除消息时正在执行的消息会被中断吗?
答:不会。移除操作只是从 MessageQueue 链表中删除未执行的消息,已经被 queue.next() 取出正在执行的消息不受影响。如果需要中断正在执行的任务,需要在 handleMessage 中加入中断逻辑,例如检查 isFinishing() 标志。
【高频题4】Handler 导致内存泄漏的原因及解决方案?
标准答案(30秒): Handler 内存泄漏的根本原因是消息队列持有 Message,Message 持有 Handler,非静态内部类 Handler 持有外部类 Activity 引用,形成引用链导致 Activity 无法回收。解决方案有两种:一是使用静态内部类加弱引用,断开 Handler 对 Activity 的强引用;二是在 Activity 销毁时调用 removeCallbacksAndMessages(null) 移除所有消息,清空引用链。推荐两种方案结合使用,既避免泄漏又保证消息正常处理。
深入展开(追问后):
泄漏链路:
MessageQueue → Message → Handler → Activity
↑ ↓
└──────────── 无法释放 ─────────────┘
错误示例:
public class LeakActivity extends AppCompatActivity {
private Handler handler = new Handler() { // ❌ 非静态内部类
@Override
public void handleMessage(Message msg) {
// 处理消息
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler.sendEmptyMessageDelayed(1, 60000); // 60秒后执行
}
// ❌ 未移除消息,Activity 销毁时仍被 Message 持有
}
正确示例:
public class SafeActivity extends AppCompatActivity {
private SafeHandler handler;
private static class SafeHandler extends Handler { // ✅ 静态内部类
private final WeakReference<SafeActivity> mActivityRef;
public SafeHandler(SafeActivity activity) {
super(Looper.getMainLooper());
mActivityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
SafeActivity activity = mActivityRef.get();
if (activity != null && !activity.isFinishing()) {
// 处理消息
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new SafeHandler(this);
handler.sendEmptyMessageDelayed(1, 60000);
}
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null); // ✅ 移除所有消息
}
}
面试官追问:
追问1:为什么静态内部类不会持有外部类引用?
答:Java 中非静态内部类会隐式持有外部类的引用(通过 OuterClass.this),编译后会生成一个指向外部类的 this$0 字段。而静态内部类在编译后是独立的类,不依赖外部类实例,因此不会持有外部类引用。如果需要访问外部类,必须显式传递引用,使用 WeakReference 包装可以避免强引用导致的泄漏。
追问2:如果消息正在执行时 Activity 销毁怎么办?
答:消息执行时 Activity 已经从 MessageQueue 中取出,removeCallbacksAndMessages(null) 无法移除。需要在 handleMessage 中加入保护性检查:
@Override
public void handleMessage(Message msg) {
Activity activity = mActivityRef.get();
if (activity == null || activity.isFinishing() || activity.isDestroyed()) {
return; // 提前返回,避免访问已销毁的 Activity
}
// 处理消息
}
【高频题5】postDelayed 如何实现延迟执行?
标准答案(30秒): postDelayed 的延迟执行是通过 MessageQueue 的时间排序实现的。调用 postDelayed 时会计算消息的执行时间 when = SystemClock.uptimeMillis() + delayMillis,然后按 when 时间戳将消息插入到 MessageQueue 链表的对应位置。Looper 循环调用 MessageQueue.next() 时,如果队列头部消息的 when 大于当前时间,会计算需要阻塞的时间并调用 nativePollOnce 进入阻塞状态,等到时间到达时被唤醒返回消息执行。底层使用 Linux epoll 机制实现精确定时。
深入展开(追问后):
源码实现:
// frameworks/base/core/java/android/os/Handler.java (Android 12)
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
// ↑ 关键:计算绝对时间
}
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
return enqueueMessage(queue, msg, uptimeMillis);
}
MessageQueue 插入逻辑:
// frameworks/base/core/java/android/os/MessageQueue.java (Android 12)
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
msg.when = when;
Message p = mMessages;
boolean needWake;
// 插入链表头(最早执行)
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 按时间顺序插入链表中间
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
}
msg.next = p;
prev.next = msg;
needWake = false;
}
// 唤醒阻塞的线程
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
阻塞与唤醒:
// frameworks/base/core/java/android/os/MessageQueue.java (Android 12)
Message next() {
for (;;) {
nativePollOnce(ptr, nextPollTimeoutMillis); // 阻塞等待
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message msg = mMessages;
if (msg != null) {
if (now < msg.when) {
// 计算需要阻塞的时间
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
return msg; // 时间到达,返回消息
}
} else {
nextPollTimeoutMillis = -1; // 无消息,无限等待
}
}
}
}
面试官追问:
追问1:为什么使用 SystemClock.uptimeMillis() 而不是 System.currentTimeMillis()?
答:
SystemClock.uptimeMillis():系统启动到现在的时间(不含深度睡眠),不受系统时间修改影响System.currentTimeMillis():当前时间戳(1970至今),受系统时间修改影响
如果使用 currentTimeMillis,用户修改系统时间会导致延迟任务失效。例如延迟 10 秒执行的任务,如果用户把系统时间调快 1 小时,任务会立即执行;调慢 1 小时则会延迟 1 小时执行。使用 uptimeMillis 可以避免这个问题。
追问2:postDelayed 的精度有多高?
答:postDelayed 的精度取决于 Looper 的调度和系统负载:
- 理论精度:毫秒级(uptimeMillis 单位是毫秒)
- 实际精度:受主线程任务影响,如果主线程正在处理耗时消息,会延迟执行
- 最佳实践:不要依赖 postDelayed 实现精确定时,误差通常在 10-50ms
如果需要精确定时,应该使用 AlarmManager 或 JobScheduler。
4.2 进阶加分题(P6/P6+)
【进阶题1】Handler 异步消息和同步屏障是什么?
参考答案:
Handler 消息分为同步消息和异步消息两种类型。普通的 sendMessage 和 post 发送的都是同步消息,需要创建异步 Handler 或调用 Message.setAsynchronous(true) 才能发送异步消息。
同步屏障(Sync Barrier) 是一种特殊的 Message,它的 target 为 null。当 MessageQueue 中存在同步屏障时,所有同步消息会被阻塞,只有异步消息能够执行。这是一种优先级机制,系统内部用于优先处理紧急任务,例如 View 绘制时会通过同步屏障优先处理 VSYNC 信号。
源码验证:
// frameworks/base/core/java/android/os/MessageQueue.java (Android 12)
Message next() {
for (;;) {
synchronized (this) {
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 {
return msg; // 返回异步消息
}
}
}
}
}
应用场景:
// frameworks/base/core/java/android/view/ViewRootImpl.java (Android 12)
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); // 插入同步屏障
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
追问:为什么应用开发不推荐使用同步屏障?
答:postSyncBarrier() 和 removeSyncBarrier() 都是 @hide 方法,应用层无法直接调用。原因是同步屏障会阻塞所有同步消息,如果使用不当会导致主线程任务饿死,引发 ANR。这是系统内部的优化机制,只应该在可控场景下使用,例如 View 绘制、输入事件处理等。
【进阶题2】Handler 如何保证消息的顺序性?
参考答案:
Handler 通过 MessageQueue 的单链表结构和时间排序保证消息顺序。MessageQueue 内部维护一个按 when 字段排序的单链表,when 是消息的执行时间(uptimeMillis)。发送消息时会遍历链表找到合适的插入位置,确保链表头部是最早执行的消息。Looper 循环从链表头部取消息执行,天然保证了时间顺序。
顺序性保证:
- 同一 Handler 发送的消息:按发送顺序执行(when 相同时先发送的在前)
- 不同 Handler 发送的消息:按 when 时间戳排序执行
- 延迟消息:按 when 时间戳插入链表,晚于即时消息执行
源码验证:
// frameworks/base/core/java/android/os/MessageQueue.java (Android 12)
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
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;
}
}
return true;
}
追问:sendMessageAtFrontOfQueue 为什么会破坏顺序?
答:sendMessageAtFrontOfQueue 强制将消息插入链表头部(when = 0),无视时间顺序。如果频繁使用会导致:
- 后发送的消息优先执行,违反时间顺序
- 其他消息被推迟执行,可能饿死
- 难以调试和追踪消息执行流程
源码中 when = 0 是特殊值,表示立即执行:
public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
MessageQueue queue = mQueue;
return enqueueMessage(queue, msg, 0); // when = 0,插入头部
}
【进阶题3】多个 Handler 共享同一个 Looper 时如何工作?
参考答案:
多个 Handler 可以共享同一个 Looper 的 MessageQueue,通过 msg.target 字段区分消息的目标 Handler。发送消息时会将 Handler 自身赋值给 msg.target,Looper 取出消息后调用 msg.target.dispatchMessage(msg) 分发到对应的 Handler 处理。这种设计实现了多路复用,一个线程可以处理多个 Handler 的消息。
源码验证:
// frameworks/base/core/java/android/os/Handler.java (Android 12)
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this; // ← 关键:设置消息的目标 Handler
return queue.enqueueMessage(msg, uptimeMillis);
}
// frameworks/base/core/java/android/os/Looper.java (Android 12)
public static void loop() {
for (;;) {
Message msg = queue.next();
if (msg == null) {
return;
}
try {
msg.target.dispatchMessage(msg); // ← 通过 target 分发到对应 Handler
} finally {
msg.recycleUnchecked();
}
}
}
实际应用:
// 主线程 Looper
Looper mainLooper = Looper.getMainLooper();
// 三个 Handler 共享主线程 Looper
Handler handler1 = new Handler(mainLooper, msg -> {
Log.d("Handler", "Handler1 处理: " + msg.what);
return true;
});
Handler handler2 = new Handler(mainLooper, msg -> {
Log.d("Handler", "Handler2 处理: " + msg.what);
return true;
});
Handler handler3 = new Handler(mainLooper, msg -> {
Log.d("Handler", "Handler3 处理: " + msg.what);
return true;
});
// 消息通过 target 字段路由到正确的 Handler
handler1.sendEmptyMessage(1); // → Handler1 处理
handler2.sendEmptyMessage(2); // → Handler2 处理
handler3.sendEmptyMessage(3); // → Handler3 处理
追问:多个 Handler 会互相影响吗?
答:不会相互影响,但会共享同一个消息队列,存在以下特点:
- 消息隔离:通过
msg.target字段确保消息分发到正确的 Handler - 队列共享:所有消息在同一个队列中按时间排序,可能出现交错执行
- 性能影响:如果某个 Handler 的消息处理耗时长,会延迟其他 Handler 的消息执行
例如:
时间线:0ms 100ms 200ms 300ms
Handler1: [msg1] --------[msg2]
Handler2: [msg3]--------[msg4]
执行顺序:msg1(0ms) → msg3(100ms) → msg2(200ms) → msg4(300ms)
4.3 实战场景题
【场景题】倒计时功能在 Activity 旋转时重置,如何解决?
场景描述: 实现一个 60 秒倒计时功能,使用 Handler.postDelayed 每秒更新 UI。但当屏幕旋转时 Activity 重建,倒计时会重置为 60 秒。如何保持倒计时状态?
问题分析:
- 根本原因:屏幕旋转时 Activity 销毁重建,Handler 和倒计时状态丢失
- 错误做法:在 onDestroy 中移除 Handler 消息,导致倒计时停止
- 需求:保持倒计时状态,跨越 Activity 重建
解决方案:
方案1:使用 ViewModel(推荐)
// CountdownViewModel.java
public class CountdownViewModel extends ViewModel {
private final MutableLiveData<Integer> countdown = new MutableLiveData<>(60);
private final Handler handler = new Handler(Looper.getMainLooper());
private final Runnable countdownTask = new Runnable() {
@Override
public void run() {
Integer value = countdown.getValue();
if (value != null && value > 0) {
countdown.setValue(value - 1);
handler.postDelayed(this, 1000);
}
}
};
public LiveData<Integer> getCountdown() {
return countdown;
}
public void start() {
handler.post(countdownTask);
}
public void stop() {
handler.removeCallbacks(countdownTask);
}
@Override
protected void onCleared() {
super.onCleared();
stop();
}
}
// CountdownActivity.java
public class CountdownActivity extends AppCompatActivity {
private TextView tvCountdown;
private CountdownViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_countdown);
tvCountdown = findViewById(R.id.tv_countdown);
viewModel = new ViewModelProvider(this).get(CountdownViewModel.class);
viewModel.getCountdown().observe(this, count -> {
tvCountdown.setText(count + "秒");
});
if (savedInstanceState == null) {
viewModel.start(); // 首次创建时启动
}
}
}
方案2:使用 onSaveInstanceState(简单场景)
public class CountdownActivity extends AppCompatActivity {
private static final String KEY_COUNTDOWN = "countdown";
private TextView tvCountdown;
private Handler handler;
private int countdown = 60;
private final Runnable countdownTask = new Runnable() {
@Override
public void run() {
if (countdown > 0) {
tvCountdown.setText(countdown + "秒");
countdown--;
handler.postDelayed(this, 1000);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_countdown);
tvCountdown = findViewById(R.id.tv_countdown);
handler = new Handler(Looper.getMainLooper());
// 恢复状态
if (savedInstanceState != null) {
countdown = savedInstanceState.getInt(KEY_COUNTDOWN, 60);
}
handler.post(countdownTask);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(KEY_COUNTDOWN, countdown); // 保存状态
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!isChangingConfigurations()) {
// 只有真正销毁时才停止倒计时
handler.removeCallbacks(countdownTask);
}
}
}
追问:
1. 方案缺点?
-
方案1(ViewModel):
- 优点:状态管理清晰,生命周期安全
- 缺点:引入 Jetpack 依赖,代码量稍多
-
方案2(onSaveInstanceState):
- 优点:代码简单,无需额外依赖
- 缺点:只能保存基本数据类型,旋转时会短暂停止
2. 其他方案?
方案3:使用 Service
适合需要在后台持续运行的倒计时(如锁屏后继续计时):
public class CountdownService extends Service {
private Handler handler = new Handler(Looper.getMainLooper());
private int countdown = 60;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startCountdown();
return START_STICKY;
}
private void startCountdown() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (countdown > 0) {
// 发送广播通知 Activity 更新 UI
Intent intent = new Intent("COUNTDOWN_UPDATE");
intent.putExtra("countdown", countdown);
sendBroadcast(intent);
countdown--;
handler.postDelayed(this, 1000);
} else {
stopSelf();
}
}
}, 1000);
}
}
3. 如何优化?
- 使用 CountDownTimer:Android 提供的倒计时工具类,自动处理生命周期
- 使用 WorkManager:适合精确定时和后台任务
- 避免内存泄漏:Handler 使用静态内部类 + 弱引用
五、对比与总结
5.1 关键API对比
sendMessage 系列对比
| API | 执行时机 | 适用场景 | 注意事项 |
|---|---|---|---|
sendMessage() | 立即插入队列 | 需要传递数据的消息 | 使用 Message.obtain() |
sendEmptyMessage() | 立即插入队列 | 只需要 what 标识 | 无需创建 Message |
sendMessageDelayed() | 延迟执行 | 定时任务、延迟操作 | 使用 uptimeMillis |
sendMessageAtTime() | 指定绝对时间 | 精确定时 | 需要计算 uptimeMillis |
sendMessageAtFrontOfQueue() | 优先执行 | 紧急消息(慎用) | 破坏顺序,可能饿死 |
post 系列对比
| API | 执行时机 | 适用场景 | 注意事项 |
|---|---|---|---|
post() | 立即插入队列 | 简单 UI 更新 | 代码简洁 |
postDelayed() | 延迟执行 | 倒计时、轮询 | 需及时移除 |
postAtTime() | 指定绝对时间 | 精确定时 | 计算 uptimeMillis |
postAtFrontOfQueue() | 优先执行 | 紧急任务(慎用) | 破坏顺序 |
移除消息对比
| API | 移除范围 | 适用场景 |
|---|---|---|
removeMessages(int what) | 指定 what 的所有消息 | 取消特定类型消息 |
removeMessages(int what, Object obj) | 指定 what 和 obj 的消息 | 精确移除 |
removeCallbacks(Runnable) | 指定 Runnable 的所有消息 | 取消 post 的任务 |
removeCallbacksAndMessages(null) | 所有消息 | Activity 销毁时清理 |
5.2 核心要点速记
一句话记忆: Handler 提供 sendMessage 和 post 两大类 API,通过 MessageQueue 时间排序实现延迟执行,使用时需注意内存泄漏和及时移除消息。
3个关键点:
- 创建方式:推荐使用
new Handler(Looper.getMainLooper()),避免隐式依赖 - 消息复用:优先使用
Message.obtain(),避免频繁创建对象 - 生命周期:Activity 销毁时调用
removeCallbacksAndMessages(null)清理消息
面试官最爱问:
- sendMessage vs post 区别:底层相同,post 是 sendMessage 的简化版,Runnable 包装为 Message.callback
- 内存泄漏原因:非静态内部类 Handler 持有 Activity 引用,消息队列持有 Message,Message 持有 Handler,形成引用链
- postDelayed 原理:计算 when 时间戳,按时间排序插入 MessageQueue,Looper 通过 epoll 阻塞等待到时间唤醒执行
六、关联知识点
前置知识:
- Handler 四大核心类(Handler、Message、MessageQueue、Looper)(详见:
./01-Handler基本概念.md) - Looper.prepare() 和 Looper.loop() 工作原理
后续扩展:
- Handler 完整工作流程源码分析(详见:
./03-Handler工作流程.md) - MessageQueue 同步屏障机制
- IdleHandler 空闲消息处理
- HandlerThread 源码实现
- AsyncTask 与 Handler 的关系
相关文件:
./01-Handler基本概念.md- Handler 定义、四大核心类关系、基本工作机制./03-Handler工作流程.md- 消息发送、MessageQueue 入队、Looper 循环、消息分发完整流程