Handler Looper Message原理浅析
Handler Looper MessageQueue 原理浅析
说到Andorid线程间通信最常见的就是Handler,Handler的原理是个大厂面试必问,可见其重要程度。本文在这里从源码角度浅析一下Handler,Looper和MessageQueue
1.从Looper开始
首先我们知道,Looper从字面理解就是轮子的意思。
Looper的源码很少,区区不到300行且大半都是注释。我们直接上代码:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
可以看到Looper的构造方法里,new了一个MessageQueue,并且保存了当前的线程信息。
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
...
//在ThreadLocal中的get方法
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
prepare方法在调用时,首先去ThreadLocal中,以该线程为key,取该Looper的信息。如果有的话则抛出异常。证明每个线程只允许有一个Looper存在。
如果没有从ThreadLocal中取出,则会将该new一个新的Looper存入ThreadLocal中,并且该Looper与当前线程绑定。
prepare方法很简洁,接下来让我们看看Looper循环的主方法:Looper.loop():
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
msg.recycleUnchecked();
}
}
可以看到首先这里有个死循环,防止程序运行结束终止退出。在循环入口会从MessageQueue中取出一条消息,就是queue.next()方法。
如果成功取到消息,则会调用msg.target.dispatchMessage(msg)。
这里的msg.target就是handler,稍后会有该部分的源码。
好了,以上就是Looper的主要源码,代码量十分少,很容易理解。
接下来要看看MessageQueue
2.MessageQueue
刚刚我们看到Looper的loop()方法调用了queue.next(),该段代码起到阻塞作用。所以我们从MessageQueue的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 (;;) {
...
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
//重点在这里
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
...
}
...
}
}
这段代码信息量比较大,不过拆分来看,我们可以确定MessageQueue.next()方法调用的恰恰是Message的next变量赋值,Message是一个单链表结构,其中next属性指向下一个Message的地址。
由此得知,当mMessages有值的时候,Looper才会调用到msg.target.dispatchMessage()。
那么什么时候对mMessages进行赋值呢?
答案就在下一个非常重要的方法里:enqueueMessage()
boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
...
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;
}
Message由enqueueMessage()方法传入,在其内部对mMessages进行赋值。进而转入next()方法跳出循环,并通知Looper()调用msg.target.dispatchMessage()。
多说一嘴,大家可能对这里面这个msg.when参数比较好奇,这个when参数就是我们再调用Handler.sendMessageDelay()方法时,传入的delay时长。具体时间循环计算方法可见next(),这里不做过多解释。
貌似整体流程清晰了,谁调用这个MessageQueue的enqueueMessage方法,谁就能将一条Message发送给Looper,进而发送给Handler的dispatch()方法。
3.Handler
答案当然是Handler调用的MessageQueue的enqueueMessage()方法。
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
这段代码仅仅是举个例子,所有的Handler的post方法以及sendMessage方法,最终都会调用到sendMessageAtTime()。
接下来看看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);
}
sendeMessageAtTime()最终会调用Handler的enqueueMessage()。
结果可想而知,Hanlder的enqueueMessage()必然会调用到MessageQueue的enqueueMessage()方法:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
果然,最后我们看看Handler的dispathMessage()方法:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
整个一条闭环流程清晰可见,最终msg通过了dispatchMessage()的分发,来到了我们常见的hanldeMessage()里面。
最后为了方便大家理解,我用一张图来演示一下整个调用流程: