Handler运行机制是Android消息处理机制的上层接口. 依靠Looper, MessageQueue, Message支撑/协作.
在主线程中不能放置耗时任务, 否则会引起ANR. 所以一般耗时任务会放在子线程当中. 由于Android开发规范, 在子线程中不能进行UI操作. 不可避免地涉及进行线程之间通信问题. 所以有人说, Handler运行机制就是用来处理UI线程与子线程之间的通信的. 这仅仅是Handler运行机制的一个应用场景. 比如还可以实现子线程向子线程发送消息, 可以参考下这篇文章.
四个重要角色
Message
Message
是消息的载体, 比较重要的两个字段是 obj
与 what
字段, 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<? 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(); 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 (;;) {}
这样一个结构, 一个死循环, 不断获取 next
Message, 直到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.callback
和 mCallback.handleMessage(msg)
. msg.callback
还记得吗?就是 postxxx
类消息发送的 Runnable
对象. mCallback.handleMessage(msg)
中的mCallback则是在Handler重载的构造方法的参数. 这里一旦设置了回调,并且其handlerMessage返回值为true, 就可以实现对Hadnler的 handlerMessage
的拦截.
ps: 有什么疏漏或者错误的地方还请各位指出.
参考:
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。