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

你可能感兴趣的:(android源码解析)