试从源码角度分析Handler的post和sendMessage方法的区别和应用场景?
更多面试题请看这里:https://interview.raoyunsoft.com/
核心区别分析
通过源码分析,post()
和sendMessage()
的本质区别在于消息处理路径不同:
// 源码核心路径(简化版)
public final boolean post(Runnable r) {return sendMessageDelayed(getPostMessage(r), 0);
}private static Message getPostMessage(Runnable r) {Message m = Message.obtain();m.callback = r; // 关键:将Runnable赋值给callbackreturn m;
}public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg); // post消息走此分支} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) return;}handleMessage(msg); // sendMessage消息走此分支}
}
处理流程对比
方法 | 消息封装方式 | 处理入口 | 是否需要重写方法 |
---|---|---|---|
handler.post() | 通过getPostMessage() 封装消息(设置 msg.callback=Runnable ) | handleCallback() → msg.callback.run() | 不需要重写handleMessage() |
handler.sendMessage() | 直接创建Message对象 | 先检查mCallback.handleMessage() 再调用 handleMessage() | 需重写handleMessage() 或设置Callback |
关键源码解析
-
post()的消息处理路径
private static void handleCallback(Message message) {message.callback.run(); // 直接执行Runnable的run() }
- 消息由
post()
提交时,自动触发Runnable.run()
- 适用于无需消息内容的简单任务
- 消息由
-
sendMessage()的处理优先级
public void dispatchMessage(Message msg) {if (msg.callback == null) {if (mCallback != null) {if (mCallback.handleMessage(msg)) return; // 优先处理Callback}handleMessage(msg); // 最终调用重写的方法} }
- 支持两种处理方式:
- 通过
Handler.Callback
接口处理(可拦截消息) - 通过重写
handleMessage()
处理
- 通过
- 支持两种处理方式:
应用场景对比
场景 | 推荐方法 | 示例 | 优势 |
---|---|---|---|
更新UI控件状态 | post() | handler.post(() -> textView.setText("Done")) | 代码简洁,无需消息对象 |
携带复杂数据的跨线程通信 | sendMessage() | Message msg = handler.obtainMessage(); msg.obj = dataModel; handler.sendMessage(msg); | 支持结构化数据传输 |
需要统一处理消息的业务逻辑 | sendMessage() + Callback | new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message m) { // 集中处理所有消息 } }) | 避免继承Handler类 |
延迟执行简单任务 | postDelayed() | handler.postDelayed(task, 1000) | 内置时间控制能力 |
实战建议
-
优先用
post()
的场景- 执行
View.post()
保证线程安全更新UI - 短耗时任务(如切换按钮状态)
// 经典用法:在子线程更新UI new Thread(() -> {// ...耗时操作handler.post(() -> progressBar.setVisibility(View.GONE)); }).start();
- 执行
-
优先用
sendMessage()
的场景- 需要传递多个数据字段(用
Bundle
) - 需要消息优先级控制(
sendMessageAtFrontOfQueue()
) - 需要复用消息处理逻辑(通过
Callback
统一处理)
// 携带复杂数据 Message msg = handler.obtainMessage(MSG_TYPE_FILE); Bundle bundle = new Bundle(); bundle.putSerializable("file", fileData); msg.setData(bundle); handler.sendMessage(msg);
- 需要传递多个数据字段(用
-
避免内存泄漏
两种方法都需注意:// 正确做法:使用静态内部类+弱引用 static class SafeHandler extends Handler {private final WeakReference<Activity> mActivity;SafeHandler(Activity activity) {mActivity = new WeakReference<>(activity);}@Overridepublic void handleMessage(Message msg) {Activity activity = mActivity.get();if (activity != null) {// 安全处理消息}} }
关键结论:两种方法最终都通过
sendMessageAtTime()
发送消息,但post()
为消息添加了callback
标记,使得dispatchMessage()
直接执行Runnable.run()
,而sendMessage()
需依赖handleMessage()
或Callback
处理。根据是否需要携带数据和代码复用需求选择合适方式。