android sendmessage和post的区别,Handler的sendMessage和postDelay的区别

原来一直觉得源码都看过了,应该也差不多了,今天用到了postDelay,然后问自己postDelay和sendMessage有什么区别,是如何处理postDelay的Runnable的,然后就没有然后了;

如果你也有这个疑问那就跟我往下一起看,如果你知道,请看我说的是不是你想的,或者我说的有哪些不足之处,

1、消息入队

1.postDelayed消息入队

我们先往里追源码顺便再熟悉一下handler的知识点

public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {

//这里我们看到postDelayed还是调用自身的sendMessageDelayed,我们接着去看sendMessageDelayed

return sendMessageDelayed(getPostMessage(r), delayMillis);

}

复制代码

这里我们看到sendMessageDelayed其实也是接收一个Message,那我们回到postDelayed看看这个Message如何处理Runnable的

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {

if (delayMillis < 0) {

delayMillis = 0;

}

return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);

}

复制代码

这里我们看到是把Runnable放到了Message.callback中,然后把Message传递到sendMessageDelayed中,这样就通了

private static Message getPostMessage(Runnable r) {

//Message.obtain() 从全局池返回一个新的Message实例。使我们在许多情况下避免分配新对象

Message m = Message.obtain();

m.callback = r;

return m;

}

复制代码

现在我们接着看sendMessageAtTime

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {

//如果mQueue为空说明没有调用prepare,这个我们下面再说

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);

}

复制代码

2.sendMessage消息入队

public final boolean sendMessage(@NonNull Message msg) {

//在此我们发现postDelayed()只是把Runnable封装了一下,走的逻辑还是一样的,

return sendMessageDelayed(msg, 0);

}

复制代码

到此我们看到消息入队已经完毕,我们接着去看消费。

2、消费

我直接进Looper.loop(),顺便简单梳理一下流程

这里补一个小知识点,

线程和 Handler Looper MessageQueue 的关系是一个线程对应一个 Looper 对应一个 MessageQueue 对应多个 Handler,既然是一个MessageQueue对应多个Handler,会不会Handler_A发消息Handler_B会同时接到,答案是不会的,下面会有说。

1.获取当前线程对应的Looper

2.获取对应的MessageQueue

3.拿到msg消息

4.msg消费

public static void loop() {

//1.获取当前线程对应的Looper

final Looper me = myLooper();

if (me == null) {

throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");

}

//2.获取对应的MessageQueue

final MessageQueue queue = me.mQueue;

...

boolean slowDeliveryDetected = false;

for (;;) {

3.拿到msg消息

Message msg = queue.next(); // might block

if (msg == null) {

// No message indicates that the message queue is quitting.

return;

}

...

Object token = null;

if (observer != null) {

token = observer.messageDispatchStarting();

}

long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);

try {

4.msg消费

msg.target.dispatchMessage(msg);

if (observer != null) {

observer.messageDispatched(token, msg);

}

dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;

} catch (Exception exception) {}

...

msg.recycleUnchecked();

}

}

复制代码

说了这么久马上就到重点了不要着急,现在我们去看看第4步target是什么,

public final class Message implements Parcelable {

//在这里能看到Message是持有Handler的引用,也就是说不存在Handler_A发消息Handler_B会同时接到的问题

@UnsupportedAppUsage

/*package*/ Handler target;

}

复制代码

我们看看target是在哪赋的值

public class Handler {

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis) {

msg.target = this;

}

}

复制代码

现在我们回到第4步看msg.target.dispatchMessage(msg);是不是就明朗了,现在我们进Handler.dispatchMessage()看做什么处理了

public void dispatchMessage(@NonNull Message msg) {

//在这里,如果msg.callback != null执行handleCallback(),

if (msg.callback != null) {

handleCallback(msg);

} else {

if (mCallback != null) {

if (mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg);

}

}

复制代码

//看到这里你悟了吗

private static void handleCallback(Message message) {

message.callback.run();

}

复制代码

总结

postDelay()方法会通过getPostMessage()在消息入队之前封装成一个Message,在消费那里通过判断msg.callback是否为空来判断是否执行Runnable.run()。

Handler五花八门的post/send api们本质上无差别。只是为了让使用者在简单的情况下避免手动封装Message,只需提供一个Runnable即可

只是一些个人的总结,如果有不通的地方欢迎大家交流,错别字也请指出来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值