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

    推荐阅读