hi 大家好,我是 DHL。就职于美团、快手、小米。公众号:ByteCode,分享有用的原创文章,涉及鸿蒙、Android、Java、Kotlin、性能优化、大厂面经。
在 Android 中 Handler 是用来处理线程间通信的一种机制,而 Handler 的 post(Runnable r) 和 sendMessage(Message msg) 方法都是处理线程间通信的重要方法,在面试中也是高频面试题。
它允许你发送一个 Message 或者 Runnable 对象到 Handler 关联的消息队列(MessageQueue)中。但是它们在使用方式、应用场景以及内部实现上有所区别。
内部源码实现不一样
post (Runnable r)
当调用 post(Runnable r) 方法时,会调用 getPostMessage(r) 创建一个 Message 对象,将 Runnable 对象赋值给 Message 的 callback 字段。
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
然后调用 sendMessageDelayed(Message msg, long delayMillis) 方法将其发送到消息队列中。这个过程是同步的,即立即将消息加入队列中。
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
// ...省略部分代码...
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
// ...省略部分代码...
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// ...省略部分代码...
boolean sent = queue.enqueueMessage(msg, uptimeMillis);
// ...省略部分代码...
return sent;
}
sendMessage (Message msg)
而 sendMessage(Message msg) 方法直接将 Message 对象加入到 MessageQueue 中,如果需要延迟发送,也可以通过 sendMessageDelayed(Message msg, long delayMillis) 实现, Message 对象可以携带数据。
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
// ...与post相同的实现...
}
// sendMessageAtTime和enqueueMessage与post中的实现相同
两者的主要区别在于:
-
post(Runnable r)用于发送一个Runnable任务,将Runnable对象赋值给Message的callback字段,然后将其发送到MessageQueue中。 -
sendMessage(Message msg)用于发送一个可以携带数据的Message对象到MessageQueue中。
无论通过那种方式,最终都会生成 Message 对象加入到 MessageQueue 中,然后 Looper 从消息队列中取出消息,分发给 Handler 的 dispatchMessage(Message msg) 方法分发处理。这两种消息虽然都在 dispatchMessage 方法中,但是消息的优先级不一样。
消息的优先级不同
Handler 的 dispatchMessage(Message msg) 方法是用来分发消息的核心逻辑。
当一个消息被 Looper 从 MessageQueue 中取出后,Looper 会调用 Handler 的 dispatchMessage(Message msg) 方法来处理这个消息。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 如果消息中有Runnable回调,则执行它
handleCallback(msg);
} else {
// 如果消息没有Runnable回调,则直接处理消息
if (mCallback != null) {
// 如果Handler有Callback,则尝试由Callback处理
if (mCallback.handleMessage(msg)) {
return;
}
}
// 如果没有Callback或Callback没有处理消息,则由handleMessage方法处理
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
public void handleMessage(Message msg) {
// 需要由子类覆盖此方法来处理消息
}
在 dispatchMessage(Message msg) 方法中,首先检查 Message 对象的 callback 字段是否为空。如果不为空,说明这个消息是通过 post(Runnable) 方法发送的,因此它会直接执行这个 Runnable。
如果 Message 对象的 callback 字段为空,那么 Handler 会检查 mCallback(一个 Handler.Callback 对象) 是否为空,如果不为空,并且 mCallback 的 handleMessage() 方法返回 true,表示消息已被处理,流程结束。
Handler.Callback callback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// 处理消息
return true; // 如果消息被处理,返回true
}
};
// 创建Handler时传入Callback
Handler handler = new Handler(callback);
如果 mCallback 为空,或者 mCallback 的 handleMessage() 方法返回 false,那么最后会调用 Handler 的 handleMessage(Message msg) 方法来处理这个消息。我们只需要在自己的 Handler 子类中覆盖 handleMessage(Message msg) 方法即可。
public class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
// 在这里处理消息
// 通过检查`Message`对象的`what`字段来区分不同类型的消息,并进行相应的处理
}
}
如果你在非主线程中创建 Handler 的实例,你需要确保该线程已经准备好了 Looper,否则 Handler 将无法正常工作.
使用场景不一样
post (Runnable r)
通常用于在指定的线程(通常是主线程)中执行一段代码,无需传递数据或者需要传递的数据可以通过外部类或者闭包来提供。
sendMessage (Message msg)
适用于需要传递数据或者需要跨线程通信的场景,通过 Message 对象可以携带数据,并由 Handler 在目标线程中处理这些数据。
总结来说,post(Runnable r) 适用于简单的任务,而 sendMessage(Message msg) 适用于需要传递数据和复杂线程间通信的场景。
全文到这里就结束了,感谢你的阅读,如果文章对你有帮助,欢迎 在看、点赞、分享 给身边的小伙伴,你的点赞是我持续更新的动力。
更多大厂面试题,欢迎前往微信搜索小程序「猿面试」查看。微信小程序(猿面试)包含了 Java、Android、鸿蒙和ArkTS、设计模式、算法和数据结构 相关内容,
Hi 大家好,我是 DHL,大厂程序员,公众号:ByteCode ,在美团、快手、小米工作过。分享有用的原创文章,涉及鸿蒙、Android、Java、Kotlin、性能优化、大厂面经。
推荐阅读:
开源新项目
-
云同步编译工具(SyncKit),本地写代码,远程编译,欢迎前去查看 SyncKit
-
KtKit 小巧而实用,用 Kotlin 语言编写的工具库,欢迎前去查看 KtKit
-
最全、最新的 AndroidX Jetpack 相关组件的实战项目以及相关组件原理分析文章,正在逐渐增加 Jetpack 新成员,仓库持续更新,欢迎前去查看 AndroidX-Jetpack-Practice
-
LeetCode / 剑指 offer,包含多种解题思路、时间复杂度、空间复杂度分析,在线阅读