一篇就够了Handler、Looper、MessageQueue、Message解析
Handler相关源码逻辑梳理
Handler是Android SDK来处理异步消息的核心类。
子线程与主线程通过Handler来进行通信。子线程可以通过Handler来通知主线程进行UI更新。此模块涉及Handler、Looper、MessageQueue、Message,Messenger。用起来简单,真的完全吃透还是需要一定功底的。不急不躁,带你一步步慢慢梳理。
类调用流程
Message
定义包含描述等相关数据的对象, 用来传输数据。
关键代码:
- 如何复用message对象,减少内存占用
recycler判断对象是否在回收队列,在的话不允许recycler,会导致回收队列中断int flags; private static Message sPool; private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50; 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(); } public void recycle() { // 检查当前对象是否在回收队列,如果已经被加入回收队列,不允许reccyle // 队列中被recycle会导致队列中断 if (isInUse()) { return; } recycleUnchecked(); } void recycleUnchecked() { flags = FLAG_IN_USE; // 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) { // 回收队列的长度最大50 if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
- message直接发送自己
public void sendToTarget() { // target就是保存的handler引用 target.sendMessage(this); }
Looper
用于为线程运行消息循环
关键代码:
- 实例化与关联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)); } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); // 关联创建Looper的线程 }
- 在当前线程运行消息队列
public static @Nullable Looper myLooper() { // 从ThreadLocal取与当前线程关联的Looper对象 return sThreadLocal.get(); } 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; // 重置当前线程上传入IPC的标识 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; } try { msg.target.dispatchMessage(msg); } finally { // 打印日志 if (traceTag != 0) { Trace.traceEnd(traceTag); } } // 确保在发送过程中线程的身份没有损坏 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); } // 回收message msg.recycleUnchecked(); } }
- 退出looper循环
// 调用MessageQueue退出 public void quit() { mQueue.quit(false); } public void quitSafely() { mQueue.quit(true); }
MessageQueue
message队列管理
关键代码
-
实例与释放MessageQueue
MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; // 调用natvie初始化,拿到native code用作标识 mPtr = nativeInit(); } void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } synchronized (this) { if (mQuitting) { return; } mQuitting = true; if (safe) { // 已经启动的message不再销毁 removeAllFutureMessagesLocked(); } else { removeAllMessagesLocked(); } // 唤醒,退出时可能mptr被阻塞中 nativeWake(mPtr); } } private void removeAllMessagesLocked() { Message p = mMessages; while (p != null) { Message n = p.next; p.recycleUnchecked(); p = n; } mMessages = null; } private void removeAllFutureMessagesLocked() { final long now = SystemClock.uptimeMillis(); Message p = mMessages; if (p != null) { if (p.when > now) { removeAllMessagesLocked(); } else { Message n; for (;;) { n = p.next; if (n == null) { return; } // 找出队列中启动时间大于当前时间的消息 if (n.when > now) { break; } p = n; } // 中断队列,释放晚于当前时间的message p.next = null; do { p = n; n = p.next; p.recycleUnchecked(); } while (n != null); } } } @Override protected void finalize() throws Throwable { try { dispose(); } finally { super.finalize(); } } // Disposes of the underlying message queue. // Must only be called on the looper thread or the finalizer. private void dispose() { if (mPtr != 0) { nativeDestroy(mPtr); mPtr = 0; } }
-
添加和移除队列同步障碍
public int postSyncBarrier() { // uptimeMillis:自开机后,经过的时间,不包括深度睡眠的时间 // 适合做一些特殊的时间间隔计算,这里相当于一定会放到队列头 return postSyncBarrier(SystemClock.uptimeMillis()); } private int postSyncBarrier(long when) { // 我们不需要唤醒队列,因为屏障的作用是使队列停止 synchronized (this) { // 一个自增的int值,用来标识同步障碍message final int token = mNextBarrierToken++; // 这里message不设置target,用来判断是不是设置了屏障 final Message msg = Message.obtain(); msg.markInUse(); msg.when = when; msg.arg1 = token; Message prev = null; Message p = mMessages; if (when != 0) { while (p != null && p.when <= when) { prev = p; p = p.next; } } if (prev != null) { // invariant: p == prev.next msg.next = p; prev.next = msg; } else { msg.next = p; mMessages = msg; } return token; } } public void removeSyncBarrier(int token) { //从队列中移除一个同步障碍 //如果队列不再被障碍阻挡,就唤醒它 synchronized (this) { Message prev = null; Message p = mMessages; // 查找target为null并且token相等的阻碍 while (p != null && (p.target != null || p.arg1 != token)) { prev = p; p = p.next; } if (p == null) { throw new IllegalStateException("The specified message queue synchronization " + " barrier token has not been posted or has already been removed."); } // p为查找出的阻碍 final boolean needWake; if (prev != null) { // 将prev和p.next串为新队列 // 因为prev不为null,所以要移除的阻碍不是队列头,不需要唤醒 prev.next = p.next; needWake = false; } else { // 去除队列头message mMessages = p.next; // 队列为null,唤醒 // 队列不为null,是否唤起队列由队列下一个message决定,因为下一个message可能还是阻碍message needWake = mMessages == null || mMessages.target != null; } p.recycleUnchecked(); // If the loop is quitting then it is already awake. // We can assume mPtr != 0 when mQuitting is false. if (needWake && !mQuitting) { nativeWake(mPtr); } } }
-
往队列中加入message
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } // 在回收队列中的message不能被复用 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; } // 标记message不在回收队列 msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // 传入的message放入头节点 msg.next = p; mMessages = msg; // 如果队列被阻塞,需要唤醒,执行头message needWake = mBlocked; } else { // 新消息是异步的 needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; // 根据when确定把新消息插入到队列的位置 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; } // 唤醒 if (needWake) { nativeWake(mPtr); } } return true; }
-
从队列中取消息
Message next() { // 已经执行过dispose,则直接返回null 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说明后面的代码可能会引起线程阻塞 Binder.flushPendingCommands(); } // 调用native方法,阻塞一定时间 nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // 获取当前时间 final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { // 队列被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; } // 清除message的next关联 msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg; } } else { // No more messages. nextPollTimeoutMillis = -1; } // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } // 没有要处理的message,先处理idleHandler if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // 没有要运行的idleHandler,循环并等待更多 // 这个时候mBlocked标记为阻塞状态 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; // 执行idlerHandler可能错过了阻塞时间,设为0,重新检查队列是否需要阻塞 nextPollTimeoutMillis = 0; } }
Handler
发送与处理消息
关键代码:
- 创建对象和消息
public Handler(Callback callback, boolean async) { // 从TheadLocal取looper mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; } public final Message obtainMessage(int what, int arg1, int arg2) { return Message.obtain(this, what, arg1, arg2); }
- 发送消息
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } public final boolean postAtTime(Runnable r, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r), uptimeMillis); } 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); } public final boolean sendMessageAtFrontOfQueue(Message msg) { 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, 0); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }