An overview of the

Binder mechanism and Message mechanism Message system involved in the core classes Handler, Looper, Message, MessageQueue Android system components start, input, UI refresh need to be achieved through the message mechanism, in a sense, Android is driven by the message system through the conveyor belt mechanism to understand

  • Message: The Message structure carries data and attributes < package on the conveyor belt >;
  • MessageQueueThe main function of a message queue is to deliver messages to a message pool (MessageQueue.enqueueMessage) and fetch messages from the message pool (MessageQueue.next)< conveyor belt >;
  • Handler: message helper class, which sends various message events to the message pool (Handler.sendMessage) and processing corresponding message events (Handler.handleMessage)< piece worker >;
  • Looper: Continuous loop execution (Looper.loop), according to the distribution mechanism to distribute the message to the target handler < conveyor belt power system >.

Handler creates the -constructor

@Deprecated public Handler() { this(null, false); } @Deprecated public Handler(@Nullable Callback callback) { this(callback, false); } public Handler(@NonNull Looper looper) { this(looper, null, false); } public Handler(@NonNull Looper looper, @Nullable Callback callback) { this(looper, callback, false); } public Handler(@nullable Callback Callback, Boolean async) {// Anonymous classes, inner classes, or local classes must be declared static, If (FIND_POTENTIAL_LEAKS) {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()); } // You must execute looper.prepare () to obtain the Looper object, otherwise null. If (mLooper == null) {throw new RuntimeException("Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; / message queue, from Looper object mCallback = callback; // mAsynchronous = async; } @unsupportedAPPUSage public Handler(@nonnull Looper Looper, @nullable Callback Callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; } @NonNull public static Handler createAsync(@NonNull Looper looper) { if (looper == null) throw new NullPointerException("looper must not be null"); return new Handler(looper, null, true); } @NonNull public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) { if (looper == null) throw new NullPointerException("looper must not be null"); if (callback == null) throw new NullPointerException("callback must not be null"); return new Handler(looper, callback, true); }Copy the code

Methods associated with sending messages

public final boolean post(@NonNull Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r), uptimeMillis); } public final boolean postAtTime( @NonNull Runnable r, @Nullable Object token, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); } public final boolean postDelayed(@NonNull Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); } /** @hide */ public final boolean postDelayed(Runnable r, int what, long delayMillis) { return sendMessageDelayed(getPostMessage(r).setWhat(what), delayMillis); } public final boolean postDelayed( @NonNull Runnable r, @Nullable Object token, long delayMillis) { return sendMessageDelayed(getPostMessage(r, token), delayMillis); } public final boolean postAtFrontOfQueue(@NonNull Runnable r) { return sendMessageAtFrontOfQueue(getPostMessage(r)); } public final boolean sendMessage(@NonNull Message msg) { return sendMessageDelayed(msg, 0); } public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); } public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(MSG, systemclock. uptimeMillis() + delayMillis); } public boolean sendMessageAtTime(@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); return false; } return enqueueMessage(queue, msg, uptimeMillis); } private Boolean enqueueMessage(@nonnull messageQueue queue, @nonnull messageQueue queue, @NonNull Message msg, long uptimeMillis) { msg.target = this; / / the current handler assigned to MSG. The target MSG. WorkSourceUid = ThreadLocalWorkSource. GetUid (); If (mAsynchronous) {// If (mAsynchronous) {MSG. SetAsynchronous (true); } return queue.enqueueMessage(msg, uptimeMillis); MessageQueue enqueueMessage} public interface Callback {Boolean handleMessage(@nonnull Message MSG); } public void handleMessage(@nonnull Message MSG) {} Public void dispatchMessage(@nonnull Message MSG) {if (MSG. Callback! = null) { handleCallback(msg); } else { if (mCallback ! = null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); }}Copy the code

Looper core method

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)); } public static void loop() { final Looper me = myLooper(); If (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } if (me.mInLoop) { Slog.w(TAG, "Loop again would have the queued messages be executed before this one completed."); } me.mInLoop = true; Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); me.mSlowDeliveryDetected = false; for (;;) {// Start an infinite loop to read messages from the message queue, terminating the loop if the message queue exits. loopOnce(me, ident, thresholdOverride)) { return; } } } private static boolean loopOnce(final Looper me, final long ident, final int thresholdOverride) { Message msg = me.mQueue.next(); // Get the message object in the message queue, If (MSG == null) {// No message indicates that the message queue is formspapers. Return false; }... try { msg.target.dispatchMessage(msg); // The message is sent to the corresponding handler for processing if (observer! = null) { observer.messageDispatched(token, msg); } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } catch (Exception exception) { if (observer ! = null) { observer.dispatchingThrewException(token, msg, exception); } throw exception; } finally { ThreadLocalWorkSource.restore(origWorkSource); if (traceTag ! = 0) { Trace.traceEnd(traceTag); }}... // Discard the message object into the message cache pool for future reuse msg.recycleunchecked (); return true; } public static @Nullable Looper myLooper() { return sThreadLocal.get(); } public void quitSafely() { mQueue.quit(true); } public void quit() { mQueue.quit(false); }Copy the code

MessageQueue

@UnsupportedAppUsage
Message next() {
    final long ptr = mPtr;
    if (ptr == 0) {//当消息循环已经退出,则直接返回
        return null;
    }

    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.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            //当消息的Handler为空时,则查询异步消息,
            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);
                    msg.markInUse();//设置消息的使用状态,即flags |= FLAG_IN_USE
                    return msg;//成功地获取MessageQueue中的下一条即将要执行的消息
                }
            } else {
                // No more messages.  没有消息 设置为-1 无限等待
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) { //消息正在退出,返回null
                dispose();
                return null;
            }

            // 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) {//没有idle handlers 需要运行,则循环并等待。
                // No idle handlers to run.  Loop and wait some more.
                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; //去掉handler的引用

            boolean keep = false;
            try {
                keep = idler.queueIdle();//idle时执行的方法
            } 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.
        //重置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;
    }
}

//MessageQueue是按照Message触发时间的先后顺序排列的,队头的消息是将要最早触发的消息。当有消息需要加入消息队列时,会从队列头开始遍历,直到找到消息应该插入的合适位置,以保证所有消息的时间顺序。
boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {// 每一个普通Message必须有一个target
        throw new IllegalArgumentException("Message must have a target.");
    }

    synchronized (this) {
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        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();//正在退出时,回收msg,加入到消息回收池
            return false;
        }

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            //p为null(代表MessageQueue没有消息) 或者msg的触发时间是队列中最早的, 则进入该该分支
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked; //当阻塞时需要唤醒
        } else {
            //将消息按时间顺序插入到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.
        if (needWake) { //消息没有退出,我们认为此时mPtr != 0
            nativeWake(mPtr);
        }
    }
    return true;
}

//这个移除消息的方法,采用了两个while循环,第一个循环是从队头开始,移除符合条件的消息,第二个循环是从头部移除完连续的满足条件的消息之后,再从队列后面继续查询是否有满足条件的消息需要被移除。
void removeMessages(Handler h, int what, Object object) {
    if (h == null) {
        return;
    }

    synchronized (this) {
        Message p = mMessages;
	//从消息队列的头部开始,移除所有符合条件的消息
        while (p != null && p.target == h && p.what == what
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        //移除剩余的符合要求的消息
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && n.what == what
                    && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}

public int postSyncBarrier() {
    return postSyncBarrier(SystemClock.uptimeMillis());
}

//插入同步屏障消息 同步屏障消息没有target,在消息队列里头启动屏障作用,便于系统的异步消息能先得到执行
private int postSyncBarrier(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) {
        final int token = mNextBarrierToken++;
        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) {
    // 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) {
            throw new IllegalStateException("The specified message queue synchronization "
                    + " barrier token has not been posted or has already been removed.");
        }
        final boolean 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);
        }
    }
}

void quit(boolean safe) {
    if (!mQuitAllowed) {// 当mQuitAllowed为false,表示不运行退出,强行调用quit()会抛出异常
        throw new IllegalStateException("Main thread not allowed to quit.");
    }

    synchronized (this) {
        if (mQuitting) {//防止多次执行退出操作
            return;
        }
        mQuitting = true;

        if (safe) {
            removeAllFutureMessagesLocked();//移除尚未触发的所有消息
        } else {
            removeAllMessagesLocked();//移除所有的消息
        }

        //mQuitting=false,那么认定为 mPtr != 0
        nativeWake(mPtr);
    }
}
Copy the code

Message

Public static Message obtain() {synchronized (sPoolSync) {if (sPool! = null) { Message m = sPool; sPool = m.next; m.next = null; M.f lags = 0 and not in the list; // Clear in-use flag sPoolSize--; // The available size of the message pool is reduced by 1. } } return new Message(); When the message pool is empty, Public void recycle() {if (isInUse()) {// Check whether the Message is using 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. */ @UnsupportedAppUsage 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; // Flag the message as FLAG_IN_USE and clear all parameters of the message. 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) {// Add the Message object to the Message pool when the Message pool is not full next = sPool; sPool = this; sPoolSize++; // Add one to the available size of the message pool}}}Copy the code

Conclusion thinking

  1. How does the handler handle the delay in sending messages? The first delay is 20 seconds and the second delay is 10 seconds. How does the second delay ensure that the second delay is executed first
  2. What is the role of barrier messages and when are message barriers and asynchronous messages needed
  3. Why obtain() is used to create messages
  4. How does a message queue block when there are no messages