之前写过,概述了Android应用程序消息处理机制。本文在此文基础上,在源码级别上展开进行概述
简单用例
Handler的使用方法如下所示:
Handler myHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { ... } } };class myThread implements Runnable { public void run() { while (!Thread.currentThread().isInterrupted()) { Message message = Message.obtain(); message.what = TestHandler.GUIUPDATEIDENTIFIER; TestHandler.this.myHandler.sendMessage(message); message.recycle(); try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }
或者:
mHandler=new Handler();mHandler.post(new Runnable(){ void run(){ ... }});
又或者:
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(); }}
源码解析
首先看其构造函数:
new Handler()...public Handler() { this(null, false);}...public Handler(Looper looper, Callback callback) { this(looper, callback, false);}...public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { // 默认为false,若为true则会检测当前handler是否是静态类 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()); } } // 1. 获得当前线程的looper mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } //2. 获得looper上的message queue mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async;}
由此引入了两个关键对象Looper和MessageQueue。
先看 mLooper = Looper.myLooper();
这一句发生了什么:
public static Looper myLooper() { return sThreadLocal.get();}
可以看到,该方法返回一个sThreadLocal对象中保存的Looper。关于ThreadLocal类,请参考,本文不展开。
如果尚未在当前线程上运行过Looper.prepare()的话,myLooper会返回null。接下来看看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));}
可以看到该方法只是简单地新建了一个Looper对象,并将其保存在sThreadLocal中。接下来看一下Looper的构造函数。
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();}
调用完Looper.prepare()后,需调用Looper.loop()才能使消息循环运作起来,其源码如下所示:
public static void loop() { final Looper me = myLooper(); //1. 取出looper对象 if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; //2. 取出looper绑定的message queue // 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(); // loop time. long tm = 0; ... for (;;) { Message msg = queue.next(); // 3. 堵塞式在message queue中取数据 if (msg == null) { // No message indicates that the message queue is quitting. return; } ... msg.target.dispatchMessage(msg); 4. 分发message到指定的target handler ... // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { ... } msg.recycleUnchecked(); // 5. 回收message对象 ... }}
可以简单地将Looper.loop()理解成一个不断检测message queue是否有数据,若有即取出并执行回调的死循环。 接下来看一下Message类:
public final class Message implements Parcelable { public int what; public int arg1; public int arg2; public Object obj; ... /*package*/ int flags; /*package*/ long when; /*package*/ Bundle data; /*package*/ Handler target; /*package*/ Runnable callback; /*package*/ Message next; private static final Object sPoolSync = new Object(); private static Message sPool; private static int sPoolSize = 0;}
what、arg1、arg2这些属性本文不作介绍,我们把目光集中在next、sPoolSync、sPool、sPoolSize这四个静态属性上。
当我们调用Message.obtain()时,返回了一个Message对象。Message对象使用完毕后,调用recycle()方法将其回收。其中obtain方法的代码如下所示:
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message();}
可以看到,obtain方法被调用时,首先检测sPool对象是否为空,若否则将其当做新的message对象返回,并“指向"message对象的next属性,sPoolSize自减。可以看出message对象通过next属性串成了一个链表,sPool为“头指针”。再来看看recycle方法的实现:
public void recycle() { if (isInUse()) { if (gCheckRecycle) { throw new IllegalStateException("This message cannot be recycled because it is still in use."); } return; } recycleUnchecked();}void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = -1; when = 0; target = null; callback = null; data = null; synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } }}
如果message对象不是处于正在被使用的状态,则会被回收。其属性全部恢复到原始状态后,放在了链表的头部。sPool对象“指向”它,sPoolSize自增。
综上可以看出,通过obtain和recycle方法可以重用message对象。通过操作next、sPoolSync、sPool、sPoolSize这四个属性,实现了一个类似栈的对象池。
msg.target为handler类型,即向handler成员的dispatchMessage方法传入msg参数,其实现如下所示:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); }}
这里可以看到回调了各种接口。
到目前为止,我们知道了如何处理在消息队列里面的msg对象,但仍不知道msg对象是如何放到消息队列里面的。通常来说,我们通过Handler的sendMessage(msg)方法来发送消息,其源码如下所示:
public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0);}...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);}...private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);}
可知sendMessage最终会调用queue.enqueueMessage(msg, uptimeMillis)将msg对象保存至message queue中,uptimeMillis表示msg执行回调的时刻。 我们来看一下MessageQueue类的enqueueMessage方法:
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) { if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); msg.recycle(); return false; } // 1.设置当前msg的状态 msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; // 2.检测当前头指针是否为空(队列为空)或者没有设置when 或者设置的when比头指针的when要前 if (p == null || when == 0 || when < p.when) { // 3. 插入队列头部,并且唤醒线程处理msg msg.next = p; mMessages = msg; needWake = mBlocked; } else { //4. 几种情况要唤醒线程处理消息:1)队列是堵塞的 2)barrier,头部结点无target 3)当前msg是堵塞的 needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } // 5. 将当前msg插入第一个比其when值大的结点前。 msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true;}
结合注释,我们可以了解到msg push到queue中时,queue的状态的变化和处理队列的逻辑。
前文中Looper对象的loop方法中:
for (;;) { ... Message msg = queue.next(); // 3. 堵塞式在message queue中取数据 if (msg == null) { // No message indicates that the message queue is quitting. return; } ... msg.target.dispatchMessage(msg); 4. 分发message到指定的target handler ...}
可以看出,message queue的next方法被调用时,可能会发生堵塞。我们来看一看message queue的next方法:
Message next() { // 1. 判断当前loop是否已经使用过,下文会解释这个mPtr final long ptr = mPtr; if (ptr == 0) { return null; } int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; // 2. 进入死循环,直到获取到合法的msg对象为止。 for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); // 这个是什么? } // 3. 进入等待,nextPollTimeoutMillis为等待超时值 nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // 4. 获取下一个msg final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { // 当前节点为barrier,所以要找到第一个asynchronous节点 do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // 当前队列里最早的节点比当前时间还要晚,所以要进入堵塞状态,超时值为nextPollTimeoutMillis nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { // 删除当前节点,并返回 mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (false) Log.v("MessageQueue", "Returning message: " + msg); return msg; } } else { // 头结点指向null nextPollTimeoutMillis = -1; } // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } // 5. 如果当前状态为idle(就绪),则进入idle handle的代码块 // 进入idle的情况有:队列为空;队列头元素blocking; if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // 6. 本轮唤醒(next被调用)时没处理任何东西,故再次进入等待。 mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // 在一次next调用中,这个代码块只会执行一次 for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { // 如果返回true,则idler被保留,下次next的idle时会被调用。 keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf("MessageQueue", "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextPollTimeoutMillis = 0; }}
代码执行流程见注释。其中IdleHandler是一个接口:
public static interface IdleHandler { boolean queueIdle();}
IdleHandler提供了一个在MessageQueue进入idle时的一个hook point。更多时与barrier机制一起使用,使message queue遇到barrier时产生一个回调。
总结
前面涉及到的几个主要的类Handler、Looper、MessageQueue和Message的关系如下所述:
Handler负责将Looper绑定到线程,初始化Looper和提供对外API。
Looper负责消息循环和操作MessageQueue对象。
MessageQueue实现了一个堵塞队列。
Message是一次业务中所有参数的载体。
框架图如下所示:
+------------------+ | Handler | +----+--------^----+ | | send | | dispatch | | v | +----- <---+ | | | Looper | | | | | +---> -----+ | ^ enqueue| | next | | +--------v------+----------+ | MessageQueue | +--------+------^----------+ | | nativePollOnce | | nativeWake | |+-----------------v------+---------------------+ Lower Layer
最后,留意到MessageQueue中有4个native方法:
// 初始化和销毁private native static long nativeInit();private native static void nativeDestroy(long ptr);// 等待和唤醒private native static void nativePollOnce(long ptr, int timeoutMillis);private native static void nativeWake(long ptr);// 判断native层的状态private native static boolean nativeIsIdling(long ptr);
将会在后续文章中进行介绍。