源码揭秘,Handler 的 post 与 sendMessage 方法的本质区别_Java

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 对象赋值给 Messagecallback 字段。

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 对象赋值给 Messagecallback 字段,然后将其发送到 MessageQueue 中。
  • sendMessage(Message msg) 用于发送一个可以携带数据的 Message 对象到 MessageQueue 中。

无论通过那种方式,最终都会生成 Message 对象加入到 MessageQueue 中,然后 Looper 从消息队列中取出消息,分发给 HandlerdispatchMessage(Message msg) 方法分发处理。这两种消息虽然都在 dispatchMessage 方法中,但是消息的优先级不一样。

消息的优先级不同

HandlerdispatchMessage(Message msg) 方法是用来分发消息的核心逻辑。

当一个消息被 LooperMessageQueue 中取出后,Looper 会调用 HandlerdispatchMessage(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 对象) 是否为空,如果不为空,并且 mCallbackhandleMessage() 方法返回 true,表示消息已被处理,流程结束。

Handler.Callback callback = new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        // 处理消息
        return true; // 如果消息被处理,返回true
    }
};

// 创建Handler时传入Callback
Handler handler = new Handler(callback);

如果 mCallback 为空,或者 mCallbackhandleMessage() 方法返回 false,那么最后会调用 HandlerhandleMessage(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、性能优化、大厂面经。