【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