*** 之前写过一篇文章,概述了Android应用程序消息处理机制。本文在此文基础上,在源码级别上展开进行概述***
简单用例
Handler的使用方法如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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(); } } } }
|
或者:
1 2 3 4 5 6 7 8 | mHandler=new Handler(); mHandler.post(new Runnable(){
void run(){ ... } });
|
又或者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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(); } }
|
源码解析
首先看其构造函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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<? 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()); } } // 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。
Looper
先看 mLooper = Looper.myLooper();
这一句发生了什么:
1 2 3 4 | public static Looper myLooper() { return sThreadLocal.get(); }
|
可以看到,该方法返回一个sThreadLocal对象中保存的Looper。关于ThreadLocal类,请参考这里,本文不展开。
如果尚未在当前线程上运行过Looper.prepare()的话,myLooper会返回null。接下来看看Looper.prepare()的实现:
1 2 3 4 5 6 7 8 9 10 11 | 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的构造函数。
1 2 3 4 5 | private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
|
调用完Looper.prepare()后,需调用Looper.loop()才能使消息循环运作起来,其源码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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) { 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(); // 5. 回收message对象 ... } }
|
可以简单地将Looper.loop()理解成一个不断检测message queue是否有数据,若有即取出并执行回调的死循环。 接下来看一下Message类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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方法的代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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方法的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | public void recycle() { if (isInUse()) { if (gCheckRecycle) { throw new IllegalStateException("This message cannot be recycled because it " + "is still in use."); } return; } recycleUnchecked(); }
/** * Recycles a Message that may be in-use. * Used internally by the MessageQueue and Looper when disposing of queued Messages. */ 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参数,其实现如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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)方法来发送消息,其源码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 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方法中:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | 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是一个接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /** * Callback interface for discovering when a thread is going to block * waiting for more messages. */ public static interface IdleHandler { /** * Called when the message queue has run out of messages and will now * wait for more. Return true to keep your idle handler active, false * to have it removed. This may be called if there are still messages * pending in the queue, but they are all scheduled to be dispatched * after the current time. */ boolean queueIdle(); }
|
IdleHandler提供了一个在MessageQueue进入idle时的一个hook point。更多时与barrier机制一起使用,使message queue遇到barrier时产生一个回调。
总结
前面涉及到的几个主要的类Handler、Looper、MessageQueue和Message的关系如下所述:
1. Handler负责将Looper绑定到线程,初始化Looper和提供对外API。
2. Looper负责消息循环和操作MessageQueue对象。
3. MessageQueue实现了一个堵塞队列。
4. Message是一次业务中所有参数的载体。
框架图如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | +------------------+ | Handler | +----^--------+----+ | | dispatch | | send | | | v +----+ <---+ | | | Looper | | | | | +---> +----+ ^ | next | | enqueue | | +--------+------v----------+ | MessageQueue | +--------+------+----------+ | | nativePollOnce | | nativeWake | | +-----------------v------v---------------------+ Native Layer
|
最后,留意到MessageQueue中有4个native方法:
C
1 2 3 4 5 6 7 8 9 | // 初始化和销毁 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);
|
将会在后续文章中进行介绍。
共同学习,写下你的评论
评论加载中...
作者其他优质文章