MessageQueue

244 阅读5分钟

MessageQueue

	private native static long nativeInit();
    private native static void nativeDestroy(long ptr);
    private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
    private native static void nativeWake(long ptr);
    private native static boolean nativeIsPolling(long ptr);
    private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);

    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        // mPtr c++层messagequeue指针
        mPtr = nativeInit();
    }

阻塞取消息next()

	Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
        // 未初始化C++层messageQueue返回null消息
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        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;
                // 当前第一个message target属性为null, 即该消息为同步屏障消				    // 息, 将会优先获取异步消息 msg.isAsynchronous()
                // 同步屏障消息只影响在它后面的异步消息
                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循环
                    } while (msg != null && !msg.isAsynchronous());
                }
                // 获取的msg要么是同步屏障拦截遍历得到的队列第一个异步消息
                // 要么就是mMessages, 即消息队列第一个消息
                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 {
                    	// 如果满足时间要求, 则该消息符合条件, 可处理
                        // 将该消息从队列中移除
                        // 如果该消息存在prevMsg,即前面有消息, 该消息前面
                        // 一个消息指向该消息下一个消息
                        // 如果不存在prevMsg, 则说明该消息是第一个		                         // mMessages 重新复值为该消息的下一个
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        // 清空该消息的next指针
                        // 标示该消息inUse, 防止复用
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    // 消息队列没有消息, 超时时间为
                    // nextPollTimeoutMillis -1
                    nextPollTimeoutMillis = -1;
                }
                
                // 程序走到这里, 说明队列没有消息
				// 处理IdleHandler
                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();
  			  }
                
                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    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) {
                    // 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.
            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;
        }
    }

enqueueMessage

boolean enqueueMessage(Message msg, long when) {
		// target为null, 即同步屏障消息, 不允许该接口插入
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        // msg 在next方法中遍历得到之后会标示为inuse, 防止复用
        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;
            }
			// 该消息标识为inUse
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            // 如果队列消息头为null, 
            // 或者插入的消息时间为0, 即handler通过sendMessageAtFrontOfQueue接口插入队列头部的消息
            // 或者该插入消息时间小于头部消息时间
            // 则该消息成为队列头部消息,next指针指向原来队列头部信息
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                // 如果mBlocked true说明当前队列读取(next)已经阻塞,需要唤醒
                // 如果mBlocked false即当前队列仍然被正常遍历获取消息中(next)
                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.
                // 插入队列中间位置, 通常我们不需要唤醒, 插入中间显然没必要唤醒
                // 除非插入的消息是异步消息而且, 当前头部消息为同步屏障消息
                // 如果是该情况则需要唤醒, 
                // 但是如果该消息前面依旧有异步消息的话似乎也没必要唤醒, 因为前面的异步消息已经做了同样的判断操作
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    // 循环查找合适插入的位置, 要么是查找到队列尾部
                    // 要么是查找到合适的中间位置 when < p.when
                    if (p == null || when < p.when) {
                        break;
                    }
                    // 假如前面判断需要唤醒, 即mBlocked && p.target == null && msg.isAsynchronous() 为ture, 即插入的为异步消息
                    // 如果队列中存在时间比新插入的异步消息小的异步消息, 那么就没有必要唤醒
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                // 该插入消息位置在prev 和 p 之间
                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;
    }

插入同步屏障, 保证同步屏障后面的异步消息优先处理

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;
            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 {
                // 如果该屏障的位置是队列首部, 如果下一个消息target不为null, 需要唤醒
                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);
            }
        }
    }