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)
适用于需要传递数据和复杂线程间通信的场景。
全文到这里就结束了,感谢你的阅读,如果文章对你有帮助,欢迎 、点赞
、分享
给身边的小伙伴,你的点赞是我持续更新的动力。
Hi 大家好,我是 DHL,大厂程序员,公众号:ByteCode ,在美团、快手、小米工作过。分享有用的原创文章,涉及鸿蒙、Android、Java、Kotlin、性能优化、大厂面经。