方式一直接执行Message中的callBack;
方式二自定义Handler,重写其handleMessage方法。
这里我们可以明显看到,callBack的优先级会更高。这是技术点3:CallBack和handleMessage哪个会优先被执行
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
handleCallBack中就是直接通过
message.callback.run();
执行Message的runnable任务。PS:run()是Runnable接口中定义的方法
先看代码,具体分为下面的几个环节。
Message next() {
…
for (;😉 {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);//4.1 nativePollOnece
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
…屏障消息相关代码先忽略
if (msg != null) {//4.2 寻找可用message
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
…idelHandler相关代码先忽略
}
}
5.1 nativePollOnce方法
这是一个native方法,阻塞的。我们上面所说的CPU休眠也就是通过nativePollOnce这个机制来实现的。调用这个方法的时候,CPU资源会被释放掉,直到被外界唤醒。底层的实现原理对应的是linux的epoll机制,这篇文章我们就不详细去分析了。我们只要知道其方法的功能就可以了。
nativePollOnce有两个参数,ptr和timeoutMillis
ptr可以理解为一个native标记的唯一值,用来识别绑定线程的。
timeoutMillis是超时时间。主要分为三种-1,0,>0。
=-1的时候是处于无限阻塞的状态,除非被外界唤醒。
=0的时候不会阻塞,会立马执行。
>0时会阻塞对应的时间,然后释放阻塞状态。
PS:nativePollOnce的native实现其实和安卓层有一些类似,也有一个阻塞的循环队列的。底层的实现机制是epoll,由于native层不是本文的核心,这里就不扩展介绍了,感兴趣的同学可以留言,我
5.2 遍历链表,寻找可以用的message
1.因为链表我们插入时是按照执行时间去插入的,所以最先执行的Message一定在链表的最头部;
2.首先获取一下当前系统非休眠状态时间;
3.首先尝试获取链表的头部,那么说明链表中无数据。则把nextPollTimeoutMillis赋值为-1,下一个循环时,就会进入无限阻塞状态,直接被唤醒。这里对应的就是2.5 章节时讲到的native唤醒机制。
4.如果头节点不为空,则判断其执行时间和当前时间做比较;
5.如果其执行时间小于当前时间,则计算差值nextPollTimeoutMillis。并且会跳出此次Message选择流程。并且在下一次循环的时候,nativePollOnce会使用该值休眠对应的时间。保证休眠时间一到,正好到了头节点的执行时间。
6.如果其执行时间是否大于当前时间,则表明该节点是可以被执行的。把头节点改成下一级节点。并且通过Message.markInUse标记当前Message已经被使用。
7.返回上一步查到的message对象
技术点4:屏障异步消息的实现机制
1 屏障消息其实就是target为空的Message消息。
2 异步消息一定要搭配屏障消息来使用。
3 如果头节点为屏障消息时,