接上一篇分析,正如Android doc所说,Handler主要有2方面用处:
1. delay执行同一线程中的某个操作,也就是schedule message、runnable在未来的某一时刻执行;
2. 给另外一个线程发送message、runnable,让某个操作在另一个线程中执行。比如A线程只要能拿到B线程的
handler就能通过此handler在A线程中通过post message、runnable,让这些消息的处理发生在B线程中,从而实现
线程间的通信。AsyncTask就是通过在background线程中通过关联UI线程的handler来向UI线程发送消息的。为了看的
更清楚些,这里摘抄下Looper.java开头处给的一个典型例子:
* This is a typical example of the implementation of a Looper thread, * using the separation of {@link #prepare} and {@link #loop} to create an * initial Handler to communicate with the Looper. * * <pre> * 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(); * } * }</pre>
在这里,别的线程可以通过LooperThread.mHandler来实现和它的通信。
接下来一点点分析源码,先看几个相关的:
/** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. * * @param msg A {@link android.os.Message Message} object * @return True if no further handling is desired */ public interface Callback { public boolean handleMessage(Message msg); } /** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { } /** * 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); } }
这个Callback接口里只有一个handleMessage方法返回boolean值,在后面Handler的ctor会用到,一般情况下都是null。这个接口的存在
没什么特殊的含义,只是为了让你不extends Handler就能处理消息而已(正如此方法的doc所说),类似Thread和Runnable接口的关系。
接下来是dispatchMessage方法,我们已经在上一篇分析Message的时候大概提到了。它的处理是如果message自身设置了callback,则
直接调用callback.run()方法,否则Callback接口的作用就显现了;如果我们传递了Callback接口的实现,即mCallback非空,则调用它处理
message,如果处理了(consumed)则直接返回,否则接着调用Handler自己的handleMessage方法,其默认实现是do nothing,如果你
是extends Handler,那么你应该在你的子类中为handleMessage提供自己的实现。
接下来我们首先看看Handler都有哪些关键的字段,源码如下:
final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; final boolean mAsynchronous;
mQueue来自mLooper,mLooper要么是在ctor中显式指定的要么是默认当前线程的,Handler关于Message、Runnable的所有处理都delegate给了mQueue;mCallback是用户提供的Callback实现,默认是null;mAsynchronous表示Handler是否是异步的,默认是同步的。
接下来我们来看各种各样的Handler的ctor(构造器):
/** * 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 represent 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 represent 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 represent 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; }
我们来看3个参数的版本,即Looper,Callback,boolean,默认looper是关联的当前线程的,callback是null,async是false。当然你愿意也可以分别指定这3个值。关于ctor不需要赘述,看doc、comment就可以很容易理解。
接下来是一堆Handler的obtainMessage函数,其实现都是直接调用Message的静态函数obtain,但相应的message的target字段都自动被设置成了当前的Handler对象。由于Message的源码已在上一篇中分析过了,这里一带而过。
getPostMessage(Runnable r)之类的也很简单,就是将runnable包装成一个Message,其callback字段被设置成了runnable。
接下来的一堆postxxx、sendxxx,最终会调用下面这个方法:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
在这里,message的target被设置成当前的Handler,如果是异步的Handler,则设置message也为异步的,然后入队,uptimeMillis表示绝对时间戳。这里需要提一下的是xxxAtFrontOfQueue方法,这个方法因为每次是将后来的message插在队列的前头,所以可能导致队列中的其他消息没机会得到处理(即饥饿),或得不到及时处理,所以说插队是不好的,慎用。正如其方法doc中所说,其实在我们的工作学习中,我也强烈推荐大家仔细看看相关类、方法的doc。我知道我们这类人都不喜欢写doc,所以既然能有doc那说明真的是必不可少的,挺重要的。
接下来是removeCallbacks相关的,源码:
/** * Remove any pending posts of Runnable r that are in the message queue. */ public final void removeCallbacks(Runnable r) { mQueue.removeMessages(this, r, null); } /** * Remove any pending posts of Runnable <var>r</var> with Object * <var>token</var> that are in the message queue. If <var>token</var> is null, * all callbacks will be removed. */ public final void removeCallbacks(Runnable r, Object token) { mQueue.removeMessages(this, r, token); }
其实现也都是delegate给了mQueue,有一点需要注意下就是这些方法会remove掉所有的Runnable r,而不是第一个匹配的
(注意方法名中的s,是复数而不是单数),也就是说一次remove调用可以remove掉之前好多次post的同一个runnable,
如果之前post的runnable还在队列中的话。
removeMessages、hasMessages之类的方法挺简单不过多解释。
Handler类的分析就到这了。。。(由于本人水平有限,欢迎批评指正)