A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler it is bound to a Looper. It will deliver messages and runnables to that Looper’s message queue and execute them on that Looper’s thread.
/** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ publicstaticvoidprepare(){ prepare(true); }
privatestaticvoidprepare(boolean quitAllowed){ //每个线程只允许执行一次该方法,第二次执行时线程的TLS已有数据,则会抛出异常。 if (sThreadLocal.get() != null) { thrownew RuntimeException("Only one Looper may be created per thread"); } //创建Looper对象,并保存到当前线程的TLS区域 sThreadLocal.set(new Looper(quitAllowed)); }
/** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread's copy of * this thread-local. */ publicvoidset(T value){ Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * * @return the current thread's value of this thread-local */ public T get(){ Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
/** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */ publicstaticvoidprepareMainLooper(){ prepare(false);//设置不允许退出的Looper synchronized (Looper.class) { //将当前的Looper保存为主Looper,每个线程只允许执行一次。 if (sMainLooper != null) { thrownew IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
/** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ publicstatic@NullableLooper myLooper(){ return sThreadLocal.get(); }
/** * Returns the application's main looper, which lives in the main thread of the application. */ publicstatic Looper getMainLooper(){ synchronized (Looper.class) { return sMainLooper; } }
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ publicstaticvoidloop(){ final Looper me = myLooper();//获取TLS存储的Looper对象 if (me == null) { thrownew RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue;//获取Looper对象中的消息队列
// 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(); finallong ident = Binder.clearCallingIdentity(); for (;;) { //进入loop的主循环方法 Message msg = queue.next(); // might block 可能会阻塞 if (msg == null) { // No message indicates that the message queue is quitting. // 没有消息,则退出循环 return; } ... try { msg.target.dispatchMessage(msg);//用于分发Message ... } catch (Exception exception) { ... } finally { ... } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. finallong 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();//将Message放入消息池 } }
loop() 进入循环模式,不断重复下面的操作,直到没有消息时退出循环。
Message msg = queue.next(),通过消息队列 MessageQueue 的 next() 方法从消息队列中取出一条消息 Message,如果此时消息队列中有 Message,那么 next 方法会立即返回该 Message,如果此时消息队列中没有 Message,那么 next 方法就会阻塞式地等待获取 Message ;
voidquit(boolean safe){ // 当mQuitAllowed为false,表示不运行退出,强行调用quit()会抛出异常 if (!mQuitAllowed) { thrownew IllegalStateException("Main thread not allowed to quit."); }
if (safe) { removeAllFutureMessagesLocked();//移除尚未触发的所有消息 } else { removeAllMessagesLocked();//移除所有的消息 } // We can assume mPtr != 0 because mQuitting was previously false. nativeWake(mPtr); } }
/** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. */ publicinterfaceCallback{ /** * @param msg A {@link android.os.Message Message} object * @return True if no further handling is desired */ booleanhandleMessage(@NonNull Message msg); }
publicfinalbooleansendMessageDelayed(@NonNull Message msg, long delayMillis){ if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
sendMessageAtTime
1 2 3 4 5 6 7 8 9 10
publicbooleansendMessageAtTime(@NonNull 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); returnfalse; } return enqueueMessage(queue, msg, uptimeMillis); }
sendMessageAtFrontOfQueue
该方法通过设置消息的触发时间为0,从而使 Message 加入到消息队列的队头。
1 2 3 4 5 6 7 8 9 10
publicfinalbooleansendMessageAtFrontOfQueue(@NonNull Message msg){ MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); returnfalse; } return enqueueMessage(queue, msg, 0); }
booleanenqueueMessage(Message msg, long when){ // 每一个普通Message必须有一个target if (msg.target == null) { thrownew IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) { thrownew IllegalStateException(msg + " This message is already in use."); }
synchronized (this) { if (mQuitting) {//正在退出时,回收msg,加入到消息池 IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); returnfalse; }
msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. //p为null(代表MessageQueue没有消息) 或者msg的触发时间是队列中最早的, 则进入该该分支 msg.next = p; mMessages = msg; needWake = mBlocked; //当阻塞时需要唤醒 } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. //将消息按时间顺序插入到MessageQueue。一般地,不需要唤醒事件队列,除非 //消息队头存在barrier,并且同时Message是队列中最早的异步消息。 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. //消息没有退出,我们认为此时mPtr != 0 if (needWake) { nativeWake(mPtr); } } returntrue; }
int pendingIdleHandlerCount = -1; // 循环迭代的首次为-1 int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } //阻塞操作,当等待nextPollTimeoutMillis时长,或者消息队列被唤醒,都会返回 nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) { // Try to retrieve the next message. Return if found. finallong now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; //当遇到target为null的Message,说明是同步屏障,则查询异步消息 if (msg != null && msg.target == null) { // Stalled by a barrier. Find the next asynchronous message in the queue. //循环遍历找出一条异步消息,当查询到异步消息,则立刻退出循环,然后处理 do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // Next message is not ready. Set a timeout to wake up when it is ready. //当异步消息触发时间大于当前时间,则设置下一次轮询的超时时长 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { // Got a message. // 获取一条消息,并返回 mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); //设置消息的使用状态,即flags |= FLAG_IN_USE msg.markInUse(); return msg;//成功地获取MessageQueue中的下一条即将要执行的消息 } } else { // No more messages. //没有消息 nextPollTimeoutMillis = -1; }
// Process the quit message now that all pending messages have been handled. //消息正在退出,返回null if (mQuitting) { dispose(); returnnull; }
// If first time idle, then get the number of idlers to run. // Idle handles only run if the queue is empty or if the first message // in the queue (possibly a barrier) is due to be handled in the future. //当消息队列为空,或者是消息队列的第一个消息时间大于当前时间 if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. //没有idle handlers 需要运行,则循环并等待。 mBlocked = true; continue; }
if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); }
// Run the idle handlers. // We only ever reach this code block during the first iteration. //只有第一次循环时,会运行idle handlers,执行完成后,重置pendingIdleHandlerCount为0. for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler 去掉handler的引用
// Reset the idle handler count to 0 so we do not run them again. //重置idle handler个数为0,以保证不会再次重复运行 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. //当调用一个空闲handler时,一个新message能够被分发,因此无需等待可以直接查询pending message. nextPollTimeoutMillis = 0; } }
/** * Callback interface for discovering when a thread is going to block * waiting for more messages. */ publicstaticinterfaceIdleHandler{ /** * 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. */ booleanqueueIdle(); }
//往消息队列合适的位置插入了同步屏障类型的Message (target属性为null) privateintpostSyncBarrier(long when){ // Enqueue a new sync barrier token. // We don't need to wake the queue because the purpose of a barrier is to stall it. synchronized (this) { finalint token = mNextBarrierToken++; final Message msg = Message.obtain(); msg.markInUse(); msg.when = when; msg.arg1 = token;//初始化Msg时target没赋值,为null
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; } }
publicvoidremoveSyncBarrier(int token){ // Remove a sync barrier token from the queue. // If the queue is no longer stalled by a barrier then wake it. synchronized (this) { Message prev = null; Message p = mMessages; //从消息队列找到 target为空,并且token相等的Message while (p != null && (p.target != null || p.arg1 != token)) { prev = p; p = p.next; } if (p == null) { thrownew IllegalStateException("The specified message queue synchronization " + " barrier token has not been posted or has already been removed."); } finalboolean needWake; if (prev != null) { prev.next = p.next; needWake = false; } else { mMessages = p.next; 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
消息对象
每个消息用 Message 表示,Message 主要包含以下内容:
数据类型
成员变量
解释
int
what
消息类别
long
when
消息触发时间
int
arg1
参数1
int
arg2
参数2
Object
obj
消息内容
Handler
target
消息响应方
Runnable
callback
回调方法
消息池
静态变量sPool的数据类型为 Message,通过 next 成员变量,维护一个消息池;静态变量MAX_POOL_SIZE代表消息池的可用大小;消息池的默认大小为50。当消息池不为空时,可以直接从消息池中获取 Message 对象,而不是直接创建,提高效率。
消息池常用的操作方法是 obtain() 和 recycle()。
obtain
从消息池中获取消息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ publicstatic Message obtain(){ synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null;//从sPool中取出一个Message对象,并消息链表断开 m.flags = 0; // clear in-use flag 清除in-use flag sPoolSize--;//消息池的可用大小进行减1操作 return m; } } returnnew Message(); }
publicvoidrecycle(){ if (isInUse()) {//判断消息是否正在使用 if (gCheckRecycle) {//Android 5.0以后的版本默认为true,之前的版本默认为false. thrownew IllegalStateException("This message cannot be recycled because it " + "is still in use."); } return; } recycleUnchecked(); }
// 对于不再使用的消息,加入到消息池 voidrecycleUnchecked(){ // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. // 将消息标示位置为FLAG_IN_USE,并清空消息所有的参数,同时将其保留在回收对象池中 flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = UID_NONE; workSourceUid = UID_NONE; when = 0; target = null; callback = null; data = null;
synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) {//当消息池没有满时,将Message对象加入消息池 next = sPool; sPool = this; sPoolSize++;//消息池的可用大小进行加1操作 } } }