面试经历
面试官:看你简历上写着看过 Handler 机制源码,说下如何提高Message的优先级?
内心分析中:
首先,我们先分析下,这个 Message 是由 Handler 进行发送,然后添加到 MessageQueue 中,Looper 遍历 MessageQueue 获取 Message 出来执行。
而 MessageQueue 是通过时间对 Message 进行排序的,若想提高 Message 的优先级,那就是要把 Message 排在 MessageQueue 的前面,这样就会优先执行了。
而我们常用的发送 Message 的方法有:
- sendMessage
- sendEmptyMessage
- post
- sendMessageDelayed
- sendEmptyMessageDelayed
- postDelayed
其中前三个是没有延迟的,后三个可以添加延迟。既然前三个没有延迟,那么一般而言就会先排在 MessageQueue 的前面。
这个问题如此简单。
答:使用sendMessage
、sendEmptyMessage
、post
发送 Message 能够使得 Message 排在 MessageQueue 前面,所以用这三个方法能够提高 Message 的优先级。
面试官:不是。
虽然知道自己面试跪了,但是还是要带着以下心情研究下,到底是哪里出问题了?
重新分析流程
首先,我们要确认下,Message 在 MessageQueue 的排序确实是以时间进行排序。
MessageQueue 插入 Message 的方法:enqueueMessage(Message msg, long when)
,when 其实就是延迟的时间。
boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
...
msg.when = when;
Message p = mMessages;
...
if (...) {
...
} else {
...
Message prev;
//核心在这里,对 MessageQueue 进行遍历
//以 when 的值从小到大进行排序
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
...
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
...
}
return true;
}
那我们看看 sendMessage(Message msg)
的 when 值是多少:
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
sendMessage
内部其实是调用了sendMessageDelayed
方法,延迟时间为 0。
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
sendMessageDelayed
内部调用的是sendMessageAtTime
方法,这里的时间为 SystemClock.uptimeMillis() + 延迟时间
,也就是SystemClock.uptimeMillis() + 0
。
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
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);
}
sendMessageAtTime
内部调用了enqueueMessage
。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
enqueueMessage
里面调用了queue.enqueueMessage
,也就是我们最开始分析的MessageQueue 插入 Message 的方法。
总结来说,通过sendMessage(Message msg)
发送 Message,其 when 并不是为 0,而是SystemClock.uptimeMillis() + 0
。
而SystemClock.uptimeMillis()
表示系统开机到当前的时间总数,单位是毫秒。
em…
那有没有办法把 when 改为 0。这样的话,发送的 Message 消息就会一定排在 MessageQueue 前面了,因为 0 是最小的了。(当然,总不可能出现负数吧?😂)
寻找答案
我们再看下 Handler 发送 Message 消息有什么方法:
嗯?这个方法没有见过:
public final boolean sendMessageAtFrontOfQueue(Message msg) {
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, 0);
}
sendMessageAtFrontOfQueue 内部调用的是enqueueMessage
。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
What?uptimeMillis 为 0 !! 这个不就是我们所想要的吗?
先淡定,send 和 post 方法相对应的,所以 post 应该也有一个这样的方法:
public final boolean postAtFrontOfQueue(Runnable r){
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
好了,结果终于出来了!!!
使用以下方法可以提高Message的优先级:
- sendMessageAtFrontOfQueue
- postAtFrontOfQueue
新知识,GET!
猜你喜欢
这是我的公众号,关注获取第一信息!!欢迎关注支持下,谢谢!