大家平时发送消息主要是调用的两大类方法 如下两图:
send方案.png
send方案.png
光看上面这些API你可能会觉得handler能法两种消息,一种是Runnable对象,一种是message对象,这是直观的理解,但其实post发出的Runnable对象最后都封装成message对象了。
下面我们就先从send方案中的第一个sendMessage() 开始源码跟踪下:
我们以Handler的sendMessage(Message msg)为例子。
代码在Handler.java 505行
/**
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in {@link #handleMessage},
* in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
老规矩先翻译一下注释:
在当前时间,在所有待处理消息之后,将消息推送到消息队列的末尾。在和当前线程关联的的Handler里面的handleMessage将收到这条消息,
我们看到sendMessage(Message)里面代码很简单,就是调用了sendMessageDelayed(msg,0)
代码在Handler.java 565行
/**
* Enqueue a message into the message queue after all pending messages
* before (current time + delayMillis). You will receive it in
* {@link #handleMessage}, in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
注释和boolean sendMessage(Message msg)方法差不多,我就不翻译了
该方法内部就做了两件事
代码在Handler.java 592行
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
*
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
老规矩先翻译一下注释:
以android系统的SystemClock的uptimeMillis()为基准,以毫秒为基本单位的绝对时间下,在所有待处理消息后,将消息放到消息队列中。深度睡眠中的时间将会延迟执行的时间,你将在和当前线程办的规定的Handler中的handleMessage中收到该消息。
这里顺便提一下异步的作用,因为通常我们理解的异步是指新开一个线程,但是这里不是,因为异步的也是发送到looper所绑定的消息队列中,这里的异步主要是针对Message中的障栅(Barrier)而言的,当出现障栅(Barrier)的时候,同步的会被阻塞,而异步的则不会。所以这个异步仅仅是一个标记而已。
该方法内部就做了两件事
代码在Handler.java 626行
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
本方法内部做了三件事
代码在MessageQueue.java 533行
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 (this) {
// 第四步
//判断消息队列是否正在关闭
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;
}
// 第五步
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
// 第六步
//根据when的比较来判断要添加的Message是否应该放在队列头部,当第一个添加消息的时候,
// 测试队列为空,所以该Message也应该位于头部。
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
// 把msg的下一个元素设置为p
msg.next = p;
// 把msg设置为链表的头部元素
mMessages = msg;
// 如果有阻塞,则需要唤醒
needWake = mBlocked;
} else {
// 第七步
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
//除非消息队列的头部是障栅(barrier),或者消息队列的第一个消息是异步消息,
//否则如果是插入到中间位置,我们通常不唤醒消息队列,
// 第八步
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 第九步
// 不断遍历消息队列,根据when的比较找到合适的插入Message的位置。
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;
}
因为这是消息入队的流程,为了让大家更好的理解,我将上面的流程大致分为12步骤
提供两张图,让大家更好的理解入队
入队1.png
入队2.png
总结一句话就是:就是遍历消息队列中所有的消息,根据when的比较找到合适添加Message的位置。
上面是sendMessage(Message msg)发送消息机制,这样再来看下其他的send方案
代码在Handler.java 615行
/**
* Enqueue a message at the front of the message queue, to be processed on
* the next iteration of the message loop. You will receive it in
* {@link #handleMessage}, in the thread attached to this handler.
* <b>This method is only for use in very special circumstances -- it
* can easily starve the message queue, cause ordering problems, or have
* other unexpected side-effects.</b>
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessageAtFrontOfQueue(Message msg) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, 0);
}
老规矩先翻译一下注释:
在消息队列的最前面插入一个消息,在消息循环的下一次迭代中进行处理。你将在当前线程关联的Handler的handleMessage()中收到这个消息。由于它可以轻松的解决消息队列的排序问题和其他的意外副作用。
方法内部的实现和boolean sendMessageAtTime(Message msg, long uptimeMillis)大体上一致,唯一的区别就是该方法在调用enqueueMessage(MessageQueue, Message, long)方法的时候,最后一个参数是0而已。
代码在Handler.java 517行
/**
* Sends a Message containing only the what value.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
老规矩先翻译一下注释:
发送一个仅有what的Message
内容很简单,也就是调用sendEmptyMessageDelayed(int,long)而已,那么下面我们来看下sendEmptyMessageDelayed(int,long)的具体实现。
代码在Handler.java 531行
/**
* Sends a Message containing only the what value, to be delivered
* after the specified amount of time elapses.
* @see #sendMessageDelayed(android.os.Message, long)
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
老规矩先翻译一下注释:
发送一个仅有what的Message,并且延迟特定的时间发送
这个方法内部主要就是做了3件事
sendMessageDelayed(Message,long) 这个方法上面有讲解过,这里就不详细说了
代码在Handler.java 547行
/**
* Sends a Message containing only the what value, to be delivered
* at a specific time.
* @see #sendMessageAtTime(android.os.Message, long)
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
老规矩先翻译一下注释:
发送一个仅有what的Message,并且在特定的时间发送
这个方法内部主要就是做了3件事
综上所述
以上这些send方案都会从这里或者那里最终走到boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)如下图
send小结.png
代码在Handler.java 324行
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
老规矩先翻译一下注释:
将一个Runnable添加到消息队列中,这个runnable将会在和当前Handler关联的线程中被执行。
这个方法内部很简单,就是调用了sendMessageDelayed(Message, long);这个方法,所以可见boolean post(Runnable r)这个方法最终还是走到上面说到的send的流程中,最终调用boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)。
这里面调用了Message getPostMessage(Runnable r),我们来看一下。
代码在Handler.java 725行
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
代码很简单,主要是做了两件事
最后返回这个Message m。
所以我们知道boolean post(Runnable r)方法的内置也是通过Message.obtain()来获取一个Message对象m,然后仅仅把m的callback指向参数r而已。最后最终通过调用send方案的某个流程最终调用到boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
这时候聪明的同学一定会想,那么post方案的其他方法是不是也是这样的?是的,的确都是这样,这都是“套路”,那我们就用一一去检验。
代码在Handler.java 347行
/**
* Causes the Runnable r to be added to the message queue, to be run
* at a specific time given by <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* The runnable will be run on the thread to which this handler is attached.
*
* @param r The Runnable that will be executed.
* @param uptimeMillis The absolute time at which the callback should run,
* using the {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
老规矩先翻译一下注释:
将一个Runnable添加到消息队列中,这个runnable将会一个特定的时间被执行,这个时间是以android.os.SystemClock.uptimeMillis()为基准。如果在深度睡眠下,会推迟执行的时间,这个Runnable将会在和当前Hander关联的线程中被执行。
方法内部也是先是调用getPostMessage(Runnable)来获取一个Message,这个Message的callback字段指向了这个Runnable,然后调用sendMessageAtTime(Message,long)。
代码在Handler.java 372行
/**
* Causes the Runnable r to be added to the message queue, to be run
* at a specific time given by <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* The runnable will be run on the thread to which this handler is attached.
*
* @param r The Runnable that will be executed.
* @param uptimeMillis The absolute time at which the callback should run,
* using the {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*
* @see android.os.SystemClock#uptimeMillis
*/
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
这个方法的翻译同上,这个方法和上个方法唯一不同就是多了Object参数,而这个参数仅仅是把Message.obtain();获取的Message的obj字段的指向第二个入参token而已。最后也是调用sendMessageAtTime(Message,long)。
代码在Handler.java 396行
/**
* Causes the Runnable r to be added to the message queue, to be run
* after the specified amount of time elapses.
* The runnable will be run on the thread to which this handler
* is attached.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
*
* @param r The Runnable that will be executed.
* @param delayMillis The delay (in milliseconds) until the Runnable
* will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed --
* if the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
这个方法也很简单,就是依旧是通过getPostMessage(Runnable)来获取一个Message,最后调用sendMessageDelayed(Message,long)而已。
代码在Handler.java 416行
/**
* Posts a message to an object that implements Runnable.
* Causes the Runnable r to executed on the next iteration through the
* message queue. The runnable will be run on the thread to which this
* handler is attached.
* <b>This method is only for use in very special circumstances -- it
* can easily starve the message queue, cause ordering problems, or have
* other unexpected side-effects.</b>
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean postAtFrontOfQueue(Runnable r)
{
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
这个方法也很简单,就是依旧是通过getPostMessage(Runnable)来获取一个Message,最后调用sendMessageAtFrontOfQueue(Message)而已。
Handler的post方案的如下方法
所以我们可以这样说:
Handler的发送消息(障栅除外),无论是通过send方案还是pos方案最终都会做走到 boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) 中
消息发送.png