Android MessageQueue与Message详解
【Android MessageQueue与Message详解】上一篇的地址为 Android Handler源码解析
通过上两篇的讲解,我们知道线程会一直阻塞在Looper的loop方法中,并且调用其MessageQueue的next()方法得到其Message,然后去执行,而Handler在发送消息时,其实是将消息发送给其绑定的MessageQueue。
同样带着问题去探索。
1、Handler会调用queue.enqueueMessage(msg, uptimeMillis)将消息入队,并指定Message的时间,那么MessageQueue是通过何种数据结构来将Message入队,并且能正确的根据当前时间执行MessageQueue(因为Message是带有时间的)?
2、线程得到当前的Message之后,是如何来进行执行的?
一、解决第一个问题,MessageQueue存储的数据结构:
我们首先看一下Message的源码:
public final class Message implements Parcelable { Handler target;
// sometimes we store linked lists of these things
Message next;
......
}
可以看出,每个Message都有一个指向自己的引用,也就是说,它是采用数据结构中的链表进行存储,那么,在不考虑每个Message的时间的情况下,如果有新的Message传入,那么只需要将MessageQueue的最后一个Message的引用指向传入的Message即可。
我们来看一下MessageQueue的enqueueMessage(msg, uptimeMillis)源码看看是如何将Message入队的,其中代码中加入了讲解的注释:
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
} //在这里使用synchronized同步代码块,防止多线程导致的异步操作混乱。
synchronized (this) {
//如果当前MessageQueue是处于退出状态的,那么要直接返回false,即入队失败
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}//下面即是进行Message链表的插入操作,需要注意的是,MessageQueue中有一个mMessages引用,始终指向Message链表的头节点,也就是第一个Message
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//下面即是使用插入判断,那么插入的依据是什么呢?MessageQueue是根据Message所执行的时间来进行插入的,即如果比其中的Message时间小,就应该插入到此Message的前面
//因为上面执行了Message p = mMessages;
也就是说p是指向头部的引用,如果头结点为空,或者需要插入的Message的执行时间比头结点还小,那么就应该让插入的Message成为头结点
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
}
//下面即是一个链表的插入操作,可以看出prev是指向需要插入的Message的前一个结点,p是指向需要插入的Message的后一个结点
else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;
;
) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p;
// invariant: p == prev.next
prev.next = msg;
}// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
二、解决第二个问题,线程得到当前的Message之后,是如何来进行执行的:
我们先看一下Looper的loop方法:
public static void loop() { . . . . . . . . . for (;
;
) {
//可以看出来,线程在此处循环的从MessageQueue中取出下一个Message。
Message msg = queue.next();
// might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}//Message的target是一个Handler对象,即调用了Handler的dispatchMessage方法将Message传过去来进行处理。
msg.target.dispatchMessage(msg);
. . . . . . . . .
}
}
我们在来看一下其调用Handler的dispatchMessage方法:
public void dispatchMessage(Message msg) { /**
Message中的callback即是一个Runnable对象,我们在执行post(Runnable runnable)方法时,其实是让
Message的callback指向我们写的Runnable对象,然后当消息被传送到Handler时,会先执行其中的Runnable, 下面就是handleCallback的源码
private static void handleCallback(Message message) {
message.callback.run();
}
可以看出本质上是直接调用Runnable的run()方法。
**/
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//最后调用自己的handleMessage方法来进行消息的处理,这也就是为什么我们在写一个Handler对象时必须覆盖它的handleMessage方法。
handleMessage(msg);
}
}
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- Docker应用:容器间通信与Mariadb数据库主从复制
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量
- android第三方框架(五)ButterKnife
- 第326天
- Shell-Bash变量与运算符
- Android中的AES加密-下
- 逻辑回归的理解与python示例
- 带有Hilt的Android上的依赖注入
- Guava|Guava RateLimiter与限流算法