Handler消息机制的源码深度分析
说起Handler机制,难免会提到四大类Handler、MessageQueue、Message、Looper.
我们先不从代码说起,而是从我们的习惯用法说起,在我们使用Handler的时候,普遍用法如下:
Handler myHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } };
我们来看看Handler的构造方法:
public Handler() { this(null, false); }
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; }
我们看这句代码
mLooper = Looper.myLooper();
好了,我们主角之一Looper闪亮登场了。Looper类其实是一个调度者的角色,它负责循环处理消息。我们来看一下Looper.myLooper的源码:
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
单单这么写代码,获取到的Looper肯定为Null。那么平时我们在Activity中这么写代码,就没有问题呢,主要是因为Activity线程已经给Handler机制做了准备工作,我们知道Activity运行在UI线程中,也叫做主线程或Main线程,该线程启动的入口是在ActivityThread.main方法中:
public static void main(String[] args) { ..... Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } ....... Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
看到两行标红的代码了吧,第一句Looper.prepareMainLooper(),我们看一下源码:
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
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被设置了Looper对象,本质上是把当前线程和该looper对象作为一个键值对存放到sThreadLocal,如下代码所示:
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
这样在调用Looper.myLooper的时候就能获取到当前线程的Looper对象了。
Looper对象创建完之后,还需要调用Looper.loop方法来开始工作,UI线程在ActivityThread.main方法中已经主动调用了该方法(如上面第二个红行),所以开发者就不用再去手动调用了,我们可以在Main线程中直接创建Handler就行了,而不用考虑Looper的问题。相反地,如果我们是在非UI线程中创建的Handler,则需要手动调用Looper.prepare()方法和Looper.loop()方法,默认情况下,此handler对象是使用的当前子线程的Looper对象,消息处理也是在当前子线程中做的。如果我们想在子线程中发送消息,然后在UI线程中处理,如果我们的Handler是在子线程中创建的,我们可以用Looper.getMainLooper()方法获取到UI线程的looper对象,然后传给Handler,如下面方式创建:
Handler myHandler = new Handler(Looper.getMainLooper()){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } };
回到正题,继续说Looper.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(); } }
根据代码可看出,loop()方法的大致逻辑就是不断地从queue中取Message,然后调用msg.target.dispatchMessage方法,不出意外地就是会最终调用到自己创建的handler.handleMessage方法。好了,除了Handler和Looper,另外两个主角MessageQueue和Message也出现了。MessageQueue对象是在创建Looper的时候创建的,它是包含在Looper对象里面的。如下面所示:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
Handler在发送消息的时候,不管直接调用的是哪个API,最终调用的是sendMessageAtTime方法,我们来看一下该方法源码:
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); }
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
根据上面源码可以看出,handler发送消息就是把一个Message放入到mQueue里面,等待Looper从中取出来处理,而这个mQueue就是与handler绑定的looper里面的MessageQueue。而上面enqueueMessage方法,可以看出,msg.target会自动赋值为当前Handler对象的引用,也就是说是哪个handler发送的消息,该消息的target就是哪个handler,这个与Looper.loop方法里面的某句代码也对应上了。
到这里整个Handler机制就说完了,Handler里面还有异步地概念,这个不怎么常用,感兴趣的同学可以去研究研究。