【Android】Handler 工作原理
概述
Handler 是 Android 中用来进行线程间通信的一种方式,通过它可以将其他线程的任务切换到 Handler 所在的线程中执行,比如任务线程更新 UI,另外 IntentService、AsyncTask 等都使用到了 Handler 来进行线程的切换。
Handler 的运行主要依赖于 MessageQueue 和 Looper 的协助,简单的说就是 Handler 持有 MessageQueue 和 Looper对象,MessageQueue 用于存放其他线程发送过来的 Message,Looper 主要用于 MessageQueue 中取出 Message 然后交给 Handler 去执行,这样便完成了任务在不同线程的切换。
MessageQueue
如上文所述,MessageQueue 是用于存放消息的类,其内部维持这一个链表,链表的节点就是 Message。它提供了 enqueueMessage() 来进行插入新的消息,提供next() 从链表中取出消息,值得注意的是next()会循环地从链表中取出 Message 交给 Handler,但如果链表为空的话会阻塞这个方法,直到有新消息到来。
enqueueMessage() 和 next() 源码:
boolean enqueueMessage(Message msg, long when) {
//target 即为 Handler
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; //用于判断是否唤醒 next() 执行,当链表为空时 next() 会阻塞
//按时间顺序找到 msg 应插入的位置
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) {
//调用 native 方法唤醒 next() 执行
nativeWake(mPtr);
}
}
return true;
}
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();
}
/**
* nativePollOnce 用于阻塞 native 层中的 MessageQueue
* ptr是 native 层的 MessageQueue 的指针
* nextnextPollTimeoutMillis 是 MessageQueue 阻塞时间
* -1 表示持续阻塞,0 表示不阻塞,> 0表示阻塞时间(毫秒)
*/
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
/**
* 发现一个消息屏障,找出链表中的第一个异步消息执行
* 消息屏障:即 target == null,这个屏障之后的所有同步消息都不会被执行,
* 即使时间已经到了也不会执行。
*/
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; //表示没阻塞,enqueueMessage() 中会判断
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.
//没有消息时,设为 -1 阻塞
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
//当空闲任务小于0时,进入下一次循环,由于
// nextPollTimeoutMillis = -1; 而会阻塞
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
/**
* 处理空闲任务
*/
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
//在处理空闲任务时可能会有新的 Message 加入队列,故设为 0 试探是否有新的消息
nextPollTimeoutMillis = 0;
}
}
Looper
Looper 主要用于从 MessageQueue 中取出消息,然后调用Handler 执行,它提供的 loop()是个无限循环的函数,会不断地从消息队列中取出消息。在非 UI 线程中 Handler 之前通常会先使用Looper.prepare(),这个函数会去创建一个 Looper 实例,然后把它加入该线程 ThreadLocal 中,ThreadLocal 是一个线程的内部储存类,ThreadLocal 中的数据其他线程将无法访问。更多 ThreadLocal。
Looper 的退出方式有两种,quit()和quitSafely(),quit()调用时直接退出,而quitSafely()要等到处理完已有的所有消息后才退出。
另外 Looper 还提供了 prepareMainLooper() 来创建 UI 线程的 Looper,这个方法会在 ActivityThread 的 main()中被调用,同时也提供getMainLooper()来获取 UI 线程的 Looper,所以在 UI 线程中使用 Handler 之前并不需要调用 Looper.prepare()。
Looper.prepare()中会先判断线程是否有 Looper 实例,没有就创建一个 Looper 实例,然后加入本线程的 ThreadLocal 中。
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
//一个线程只能有一个 Looper 实例
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
Looper主要的方法时 loop(),它是一个无限循环的函数,只有当消息队列返回 null 是才会结束,而消息队列返回空则需要调用 Looper 的quit()或quitSafely(),这两个方法会进一步调用 MessageQueue 的quit()方法,即 Looper 退出时才能结束循环。
loop()中调用 MessageQueue 的next()来获取消息,所以当next()阻塞时,loop()也将阻塞。如过获得了 Message,将调用 msg.target.dispatchMessage(),这个msg.target就是Handler,Message 对象中有一个 Handler 成员变量,当 Handler 把消息加入 MessageQueue 时,调用msg.target = this将自己传到 Message 当中。
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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//无限循环
for (;;) {
//从消息队列中获取消息,如过next() 阻塞,loop也将阻塞
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);
}
//msg.target 为 Handler 对象,即把 msg 交给 Handler 对象执行
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
Handler
在 Handler 机制中,主要的功能都由 MessageQueue 和 Looper 去实现了,Handler 主要用于往队列里插入 Message 和 执行 Looper 取出的 Message 两个过程。
在 Handler 的构造方法中, Handler 会去获取本线程的 Looper 对象 和 MessageQueue,所以如果线程之前为调用Looper.prepare()就会出现异常。
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
//如果不是 Looper 线程则出现异常
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//获取MessageQueue
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Handler 提供 post 和 send 两个系列的方法往队列里插入消息,但最终都将调用下面这个方法来进行插入,并且把 Message 的 成员变量 target 设为自身,以便在loop()取出该 Message 的时候调用 Handler 执行。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//把自身赋给 target
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
当loop()取出某个 Message ,并调用msg.target.dispatchMessage() 时,将执行以下方法,最终执行定义 Handler 时执行的handleMessage()。如果为 Message 设置了Runnable,则执行 Runnable.run(),否则执行 Handle 的 成员变量
Callback 的handleMessage()(如果有),再不然就是 Handler 的成员方法 handleMessage()。
public void dispatchMessage(Message msg) {
//这个callbck是个Runnable对象,handleCallback就是执行了Runnable对象.run()
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
以上,就是 Handler 整个工作过程。
++:
《Android 开发艺术探索》
深入理解MessageQueue