tXXX() 方法都是调用 getPostMessage()
将 参数中的 Runnable 包装成 Message,再调用对应的 sendXXX()
方法。看一下 getPostMessage()
的代码:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
主要是把参数中的 Runnable 赋给 Message 的 callback
属性。
殊途同归,发送消息的重任最后都落在了 sendMessageAtTime()
身上。
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); // 调用 Messagequeue 的 enqueueMessage() 方法
}
Handler 就是一个撒手掌柜,发送消息的任务转手又交给了 MessageQueue
来处理。
再额外提一点,enqueueMessage()
方法中的参数 uptimeMillis
并不是我们传统意义上的时间戳,而是调用 SystemClock.updateMillis()
获取的,它表示自开机以来的毫秒数。
MessageQueue
enqueueMessage()
Message 的入队工作实际上是由 MessageQueue 通过 enqueueMessage()
函数来完成的。
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) { // msg 必须有 target
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) { // msg 不能正在被使用
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;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
// 插入消息队列头部,需要唤醒队列
msg.next = p;
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.
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;
}
从源码中可以看出来,MessageQueue 是用链表结构来存储消息的,消息是按触发时间的顺序来插入的。
enqueueMessage() 方法是用来存消息的,既然存了,肯定就得取,这靠的是 next()
方法。
next()
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// 阻塞方法,主要是通过 native 层的 epoll 监听文件描述符的写入事件来实现的。
// 如果 nextPollTimeoutMillis = -1,一直阻塞不会超时。
// 如果 nextPollTimeout