您的位置:首页 > 产品设计 > UI/UE

Android MessageQueue与Message详解

2016-07-06 08:34 405 查看
上一篇的地址为 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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: