简述:
Handler在Android里面到处可见。一般用于多线程消息交互、主线程刷新、延时/定时处理等。今天来揭开Handler背后的秘密。
PS: 如果有想替代Handler用开源库的话,大名鼎鼎的RxJava就是干这事的。
相关代码:
- frameworks/base/core/java/android/os/Handler.java
- frameworks/base/core/java/android/os/MessageQueue.java
- frameworks/base/core/java/android/os/Looper.java
介绍:
从Handler默认构造函数入手:
110 /**
111 * Default constructor associates this handler with the {@link Looper} for the
112 * current thread.
113 *
114 * If this thread does not have a looper, this handler won't be able to receive messages
115 * so an exception is thrown.
116 */
117 public Handler() {
118 this(null, false);
119 }
从注释可以看出,Handler绑定了Looper,而Looper又记录了当前线程等信息,且认为是Handler跟线程强相关。
找到参数为(null, false)的方法,
175 /**
176 * Use the {@link Looper} for the current thread with the specified callback interface
177 * and set whether the handler should be asynchronous.
178 *
179 * Handlers are synchronous by default unless this constructor is used to make
180 * one that is strictly asynchronous.
181 *
182 * Asynchronous messages represent interrupts or events that do not require global ordering
183 * with respect to synchronous messages. Asynchronous messages are not subject to
184 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
185 *
186 * @param callback The callback interface in which to handle messages, or null.
187 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
188 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
189 *
190 * @hide
191 */
192 public Handler(Callback callback, boolean async) {
193 if (FIND_POTENTIAL_LEAKS) {
194 final Class<? extends Handler> klass = getClass();
195 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
196 (klass.getModifiers() & Modifier.STATIC) == 0) {
197 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
198 klass.getCanonicalName());
199 }
200 }
201
202 mLooper = Looper.myLooper();
203 if (mLooper == null) {
204 throw new RuntimeException(
205 "Can't create handler inside thread " + Thread.currentThread()
206 + " that has not called Looper.prepare()");
207 }
208 mQueue = mLooper.mQueue;
209 mCallback = callback;
210 mAsynchronous = async;
211 }
关键代码mLooper = Looper.myLooper()继续进去看
70 // sThreadLocal.get() will return null unless you've called prepare().
71 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
...
250 /**
251 * Return the Looper object associated with the current thread. Returns
252 * null if the calling thread is not associated with a Looper.
253 */
254 public static @Nullable Looper myLooper() {
255 return sThreadLocal.get();
256 }
从sThreadlocal里面取出Looper。sThreadLocal,看名字意思就可以大概知道线程本地记录,他可以记录了一个Looper对象(要详细了解ThreadLocal,可以搜下)。既然是get,一般对应的可以找到set的地方。找遍Looper代码可以发现只有一个set的地方:
91 /** Initialize the current thread as a looper.
92 * This gives you a chance to create handlers that then reference
93 * this looper, before actually starting the loop. Be sure to call
94 * {@link #loop()} after calling this method, and end it by calling
95 * {@link #quit()}.
96 */
97 public static void prepare() {
98 prepare(true);
99 }
100
101 private static void prepare(boolean quitAllowed) {
102 if (sThreadLocal.get() != null) {
103 throw new RuntimeException("Only one Looper may be created per thread");
104 }
105 sThreadLocal.set(new Looper(quitAllowed));
106 }
从代码可以看出,每个线程只会有一个Looper。prepare只能调用一次,如果调用第二次,就会丢出RuntimeException。继续看Looper的构造函数:
267 private Looper(boolean quitAllowed) {
268 mQueue = new MessageQueue(quitAllowed);
269 mThread = Thread.currentThread();
270 }
Looper创建了一个MessageQueue,同时引用了当前线程对象。到这里,Handler多线程消息交互,就可以推测出,应该就是靠的这个mQueue了(参数quitAllowed用于区别当前线程是否是主线程)。
我们回到Handler的构造函数往下看,203行会有一个判断mLooper是否为空。如果是空,就会丢出异常。这里是为了保证在Handler对象初始化的时候,这个mLooper一定绑定过一个线程,也就是一定调用过Looper的prepare方法。在Looper里面的类介绍里面也给出了示例用法:
27 /**
28 * Class used to run a message loop for a thread. Threads by default do
29 * not have a message loop associated with them; to create one, call
30 * {@link #prepare} in the thread that is to run the loop, and then
31 * {@link #loop} to have it process messages until the loop is stopped.
32 *
33 * <p>Most interaction with a message loop is through the
34 * {@link Handler} class.
35 *
36 * <p>This is a typical example of the implementation of a Looper thread,
37 * using the separation of {@link #prepare} and {@link #loop} to create an
38 * initial Handler to communicate with the Looper.
39 *
40 * <pre>
41 * class LooperThread extends Thread {
42 * public Handler mHandler;
43 *
44 * public void run() {
45 * Looper.prepare();
46 *
47 * mHandler = new Handler() {
48 * public void handleMessage(Message msg) {
49 * // process incoming messages here
50 * }
51 * };
52 *
53 * Looper.loop();
54 * }
55 * }</pre>
56 */
继续构造函数的第208行,这里有个关键变量。mQueue的赋值:
208 mQueue = mLooper.mQueue;
到这里,可以总结出:
同一个线程里面,可以有多个Handler,最多只有一个Looper对象,多个Handler用的是同一个MessageQueue。
写段测试代码证实下:
package com.fy.platfromdebug;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
public class TestHandler {
private static final String TAG = "TestHandler";
public void test() {
Handler mainHandler = new Handler(Looper.getMainLooper());
MessageQueue queue = mainHandler.getLooper().getQueue();
Log.d(TAG, "mainHandler=" + mainHandler + " looper=" + mainHandler.getLooper() + " queue=" + queue);
Handler mainHandler2 = new Handler(Looper.getMainLooper());
MessageQueue queue2 = mainHandler2.getLooper().getQueue();
Log.d(TAG, "mainHandler2=" + mainHandler2 + " looper=" + mainHandler2.getLooper() + " queue=" + queue2);
}
public void test2() {
HandlerThread handlerThread = new HandlerThread("Test");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
Log.d(TAG, "handler=" + handler + " looper=" + handler.getLooper() + " queue=" + handler.getLooper().getQueue());
Handler handler2 = new Handler(handlerThread.getLooper());
Log.d(TAG, "handler2=" + handler2 + " looper=" + handler2.getLooper() + " queue=" + handler2.getLooper().getQueue());
}
}
从log输出,可以证实我们的分析。
2019-01-07 10:26:30.492 22032-22032/com.fy.platfromdebug D/TestHandler: mainHandler=Handler (android.os.Handler) {459885c} looper=Looper (main, tid 2) {4d34765} queue=android.os.MessageQueue@ad45c3a
2019-01-07 10:26:30.493 22032-22032/com.fy.platfromdebug D/TestHandler: mainHandler2=Handler (android.os.Handler) {f6120eb} looper=Looper (main, tid 2) {4d34765} queue=android.os.MessageQueue@ad45c3a
2019-01-07 10:26:30.496 22032-22032/com.fy.platfromdebug D/TestHandler: handler=Handler (android.os.Handler) {524ce48} looper=Looper (Test, tid 1812) {b35f4e1} queue=android.os.MessageQueue@d9c0206
2019-01-07 10:26:30.496 22032-22032/com.fy.platfromdebug D/TestHandler: handler2=Handler (android.os.Handler) {aaee0c7} looper=Looper (Test, tid 1812) {b35f4e1} queue=android.os.MessageQueue@d9c0206
这里有个疑问,平时我们实例化Handler时,也没有传过任何参数,那Handler是绑定的哪个线程呢?我们也没有调用过Looper.prepare(),代码也没丢过异常。
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
...
}
};
绑定的线程很好理解,就是实例化代码运行在哪个线程,就绑定的哪个线程。
Looper.prepare()虽然我们没调用过,不代表别人没调用过。上面的代码一般是运行在主线程,那我们肯定可以找到调用parpare的地方。在Looper里面搜索调用prepare的地方,发现Looper里面还有一个方法:
108 /**
109 * Initialize the current thread as a looper, marking it as an
110 * application's main looper. The main looper for your application
111 * is created by the Android environment, so you should never need
112 * to call this function yourself. See also: {@link #prepare()}
113 */
114 public static void prepareMainLooper() {
115 prepare(false);
116 synchronized (Looper.class) {
117 if (sMainLooper != null) {
118 throw new IllegalStateException("The main Looper has already been prepared.");
119 }
120 sMainLooper = myLooper();
121 }
122 }
这里调用了prepare方法,而这个prepareMainLooper在ActivityThread的main方法里面就调用了。所以前面的Handler绑定的是主线程。
6804 public static void main(String[] args) {
...
6822
6823 Looper.prepareMainLooper();
6824
...
6853 }
到现在为止,我们已经搞清楚Handler跟线程之前的关系了。
下次我们再来揭秘Handler背后的另一个boss, MessageQueue。