Handler由Message、MessageQueue、Looper 和Handler本身四大部分组成,我们这里分别看一下他们的实现原理和整体之间的关联
消息------Message
-
消息的复用:
Message.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(); }
- 从Message 链表的头节点-----sPool中获取第一个消息,然后更新头节点
- 清空next信息
- 重置in-use标志位
- 更新消息池size
-
消息的回收:
Message.recyclerUnchecked()
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) {//MAX_POOL_SIZE==50 next = sPool; sPool = this; sPoolSize++; } } }
- 标识消息used;
- 重置参数
- 加入到消息池
消息队列-------MessageQueue
关键:使用链表保存MessageQueue;使用一个阻塞标记标示是否列表是否为空;记录next barrier的token
.....
Message mMessages;//链表头
// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
private boolean mBlocked; //阻塞标示
// The next barrier token.
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
private int mNextBarrierToken; //分隔栏tekon
.....
>barrier是一个target为null的Message,使用postSyncBarrier(SystemClock.uptimeMillis())方法加入MessageQueue中,它的arg1参数保存着token。
>
>当从MessageQueue中取出消息时,遇到barrier会停止取出barrier后面的同步消息,称为“同步消息分隔栏”。
-
消息入队:
enqueueMessage()
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { //消息必须有一个处理它的目标Handler 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(TAG, e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); //消息入队后标记为--used msg.when = when; Message p = mMessages; boolean needWake; //添加消息到链表中 if (p == null || when == 0 || when < p.when) { //之前是空链表的时候读取消息会阻塞,新添加消息后唤醒 msg.next = p; mMessages = msg; needWake = mBlocked; } else { //插入消息到队列时,若消息队列阻塞、队列头是barrier并且当前消息是异步的时,需要唤醒队列 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; } } 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; }
-
消息出队:
MessageQueue.next()
Message next() { //如果消息的 looper 退出,就退出这个方法 final long ptr = mPtr; if (ptr == 0) { return null; } int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; //循环取出消息,没有就阻塞 for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { //获取下一个消息 final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; //当前的链表头 if (msg != null && msg.target == null) { //如果消息没有target---是barrier,向后遍历找到第一个异步的消息 do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { //如果这个消息还没到处理时间,就设置个时间过段时间再处理 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 (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); //标记这个消息在被使用 return msg; } } else { // 消息链表里没有消息了 nextPollTimeoutMillis = -1; } //如果收到退出的消息,并且所有等待处理的消息都处理完时,调用 Native 方法销毁队列 if (mQuitting) { dispose(); return null; } if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } 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 { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "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; } }
mIdleHandlers:监听MessageQueue阻塞的接口List,MessageQueue在阻塞时会遍历并调用idler.queueIdle()方法,该方法返回false则会在一次调用后移除该idler。
消息调度器----Looper
属性:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; //主线程的 Looepr
final MessageQueue mQueue; //与之管理的消息队列
final Thread mThread; //所在的线程
private Printer mLogging;
private long mTraceTag;
/* If set, the looper will show a warning log if a message dispatch takes longer than time. */
private long mSlowDispatchThresholdMs;
- Looper初始化
Looper.prepare()
:
使用ThreadLocal保证每个线程各自拥有自己一个的Looper。
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.loop()
public static void loop() { final Looper me = myLooper(); if (me == null) { //当前线程必须创建 Looper 才可以执行 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { //无限循环 Message msg = queue.next(); //从消息队列中读取消息,可能会阻塞 if (msg == null) { //当消息队列中没有消息时就会返回,不过这只发生在 queue 退出的时候 return; } //... try { msg.target.dispatchMessage(msg); //调用消息关联的 Handler 处理消息 } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } //... msg.recycleUnchecked(); //标记这个消息被回收 } }
- 无限循环取出Message,调用对应Handler的dispatchMessage()方法处理消息
- 标记消息被回收
-
Looper.quit()方法退出循环,其调用的是MessageQueue.quit()方法。
void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } synchronized (this) { if (mQuitting) { return; } mQuitting = true; if (safe) { removeAllFutureMessagesLocked(); } else { removeAllMessagesLocked(); } // We can assume mPtr != 0 because mQuitting was previously false. nativeWake(mPtr); } }
判断并更新标识位;
-
removeAllMessagesLocked();
立即把消息链表中的所有消息全部回收
- 在停止后如果 Handler 还发送消息,会返回 false,表示入队失败
- 这个方法是不安全的,一般建议使用下面那个
- removeAllFutureMessagesLocked();
- 只会将还未执行的消息回收掉
- 在调用之后添加进入的消息不会被处理,Handler.sendMessage 也会返回 false
Handler
- 主要属性:
final Looper mLooper;
final MessageQueue mQueue;
final Callback mCallback; //构造Handler时可传的自定义处理方法
final boolean mAsynchronous;
IMessenger mMessenger;`
- 消息处理方法:dispatchMessage(Message msg)
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
-
如果消息定义了callback,则调用handleCallback(msg),该方法是调用Message自身的callback方法;
private static void handleCallback(Message message) { message.callback.run(); }
-
消息的callback为null,调用mCallback的handleMessage(msg)方法,如果mCallback.handleMessage(msg)返回true,直接返回,不再调用handleMessage(msg);
mCallback是构造Handler时可传的自定义处理方法,其内部定义了一个handleMessage(Message msg)方法;
最后调用handleMessage(msg)方法。
-
发送消息
- Message-----sendMessage(Message msg)
- Runnable------post(Runnable r)
post方法会将Runnable包装为Message,然后调用sendMessageDelayed()方法;
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
sendMessage(Message msg)最后还是调用了消息队列的
enqueueMessage()
方法: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); }
-
移除消息,调用mQueue.removeMessages方法,从队列中移除消息。
public final void removeCallbacks(Runnable r){ mQueue.removeMessages(this, r, null); } public final void removeMessages(int what) { mQueue.removeMessages(this, what, null); }
参数r与Message.callback 比较