Handler运行机制

Handler运行机制是Android消息处理机制的上层接口. 依靠Looper, MessageQueue, Message支撑/协作.
在主线程中不能放置耗时任务, 否则会引起ANR. 所以一般耗时任务会放在子线程当中. 由于Android开发规范, 在子线程中不能进行UI操作. 不可避免地涉及进行线程之间通信问题. 所以有人说, Handler运行机制就是用来处理UI线程与子线程之间的通信的. 这仅仅是Handler运行机制的一个应用场景. 比如还可以实现子线程向子线程发送消息, 可以参考下这篇文章.
四个重要角色 Message
Message是消息的载体, 比较重要的两个字段是objwhat字段, obj就是需要传递消息的内容, what标志消息的类型, 方便在接收的时候处理.
MessageQueue
存储Meesage的单链表, 向外提供读取next方法, 与enqueueMessage入队操作.
Looper
维护MessageQueue, 开始工作时, 不断从MessageQueue中取出Message分发给他们的target(其实就是他们对应的handler). 一个线程中只能有一个Looper对象.
Handler
消息的发送者与消息的处理者
一个经典的例子
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }

这里通过继承Thread,创建了一个LooperThread的线程类, run方法中先调用了Looper.prepare(), 然后创建了一个Handler对象, 最后调用了Looper.loop()方法.
接下来, 我们通过源码分析看看究竟发生了什么.
Looper.Prepare
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)); }

可以看到prepare方法可以重载, 先会判断sThreadLocal.get()是否为空, 为空的话, 先new Looper(quitAllowed)创建了一个Looper对象, 然后把这个Looper对象保存在了sThreadLocal中. 可以想象当我们再次在当前线程调用Looper.prepare方法时, 这时的sThreadLocal.get()就不为空了, 会向我们抛出一个Only one Looper may be created per thread异常. 由此可以保证我们每个线程最多拥有一个Looper对象.
刚才构造Looper对象的过程中, 究竟又做了什么呢?
我们看看Looper的构造方法
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }

可以看到内容只有两行. 分别为Looper的两个成员变量赋值, 创建了一个MessageQueue, Looper绑定了当前线程.
总结下就是: Looper.prepare方法在当前线程中创建了一个Looper对象, Looper对象的创建又导致了MessageQueue对象创建. 并且绑定当前线程. (Looper和MessageQueue在一个线程中最多有一个)
创建Handler对象 Handler对象的创建我们直接来看Handler的构造方法.
/** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */ public Handler() { this(null, false); }/** * Constructor associates this handler with the {@link Looper} for the * current thread and takes a callback interface in which you can handle * messages. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. * * @param callback The callback interface in which to handle messages, or null. */ public Handler(Callback callback) { this(callback, false); }/** * Use the provided {@link Looper} instead of the default one. * * @param looper The looper, must not be null. */ public Handler(Looper looper) { this(looper, null, false); }/** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. */ public Handler(Looper looper, Callback callback) { this(looper, callback, false); }/** * Use the {@link Looper} for the current thread * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages.Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */ public Handler(boolean async) { this(null, async); }/** * Use the {@link Looper} for the current thread with the specified callback interface * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages.Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */ public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class 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(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }/** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages.Also set whether the handler * should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages.Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */ public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }

可以看到Handler的构造方法有好几个, 其实做的工作, 不外乎为他的各个成员变量赋值mLooper,mQueue,mCallback,mAsynchronous. 分析最复杂的Handler(Callback callback, boolean async)方法. Looper.myLooper()方发获得了一个Looper对象, 这个Looper对象是哪里来的呢?
/** * Return the Looper object associated with the current thread.Returns * null if the calling thread is not associated with a Looper. */ public static @Nullable Looper myLooper() { return sThreadLocal.get(); }

查看源码看到sThreadLocal.get(), 原来就是从我们在Looper.prepare()中存起来的Looper, 如果为空, 说明我们的prepare方法根本没有执行. 抛出Can't create handler inside thread that has not called Looper.prepare()异常. 接下来Handler的构造方法还做了一件事, 把Looper中维护的MessageQueue取出来赋值给了mQueue字段.
总结下: 获取当前线程的Looper对象取出来, 并把他和他维护的MessageQueue赋值给了Handler的成员变量.
这里有个问题: void handleMessage(Message msg)又是怎样被调用的呢?别急, 让我们看看Looper.loop()方法.
Looper.loop()
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the 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; // 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 (; ; ) { 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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); }final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } }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的构造方法一样, 先获得当前线程得Looper对象. 如果为空, 那一定又是没有prepare. 接下来可以看到for (; ; ) {}这样一个结构, 一个死循环, 不断获取nextMessage, 直到Message为空.
这里有个问题: 一直在说从队列中不断取Message, Message是多久放入队列的?
Message的入队时通过Handler对象的sendxxx类与postxxx类方法实现的.
  • sendxxx类
//sendEmptyMessageDelayed ==>sendMessageDelayed public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } //sendMessageDelayed==>sendMessageAtTime public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } //最后都调用到这里 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); }

可以看到最后都执行了boolean sendMessageAtTime(Message msg, long uptimeMillis)方法. 可以看到这里最终调用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); }

这就时我们想要的入队操作. 值得留意的是这里的msg.target = this, 入队的Message标记了发送他的Handler.
  • postxxx方法
    postxxx方法都用两个相同的特征: 都传入Runnable对象, 都最终调用了一个sendxxx方法. 所以说postxxx方法最终还是会调用enqueueMessage(queue, msg, uptimeMillis)让消息入队. 好像有一点不对? 明明传入的一个Runnable对象, 但是入队的时候, 存入其中却变成了Message?我们来看看其中一个postxxx方法.
public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); }

可以看到这里多调用了一个getPostMessage(r)方法. 这个方法就是将我们的Runnable对象封装为Message对象的关键.
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }

可以看到这里获得一个Message后, 将Message的callback字段设置为了Ruannable对象. 这下就豁然开朗了.
接下来接着看在MessageQueue中拥有Handler发送来的消息后, 会如何进行操作. 在死循环中. msg.target.dispatchMessage(msg) 让msg的target(也就是发送他的Handler)去分发事件.
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }

这里的逻辑就非常清晰了, 刚才想弄清楚的Handler的handleMessage就是再这里最后调用的. 除此之外, 消息的分发还有两条路径msg.callbackmCallback.handleMessage(msg). msg.callback还记得吗?就是postxxx类消息发送的Runnable对象. mCallback.handleMessage(msg)中的mCallback则是在Handler重载的构造方法的参数. 这里一旦设置了回调,并且其handlerMessage返回值为true, 就可以实现对Hadnler的handlerMessage的拦截.
【Handler运行机制】ps: 有什么疏漏或者错误的地方还请各位指出.
参考:
  • 从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露)
  • 深入理解之 Android Handler
  • <>

    推荐阅读