Android中消息机制中一些细节知识点

时隔很久,重温Android消息机制,注意到这么两个东西

MessageQueue中的IdleHandler

看MessageQueue的源码发现,里面有个IdleHandler,声明如下

/**
     * Callback interface for discovering when a thread is going to block
     * waiting for more messages.
     */
    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.
         * 在当前线程变为空闲状态的时候执行,返回值代表是否保留该对象,如果返回false,那么该对象执行一次之后会被移除。
         */
        boolean queueIdle();
    }

它体现在MessageQueue.next()方法中。

    Message next() {

        // 省略部分代码
        int pendingIdleHandlerCount = -1; // -1 only during first iteration

        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {

                // 省略部分代码

                // 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);
            }// end of synchronized (this)

            // 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("MessageQueue", "IdleHandler threw exception", t);
                }

                if (!keep) {// 由此可见,IdleHandler返回值的作用
                    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;
        }
    }

注意,这个IdleHandler的执行是每调用一次next()方法才会执行一次。

那么这个类的用处就显而易见了,当我们需要在线程空闲时执行一些操作的话,就可以利用这个类来做。使用方式如下

Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
                // do something
                return false;
            }
        });

MessageQueue中的同步阻塞器

其实,同步阻塞器的本质依旧是一个Message,只不过它的target为空。它存在于消息队列中。同步阻塞器在插入后会返回一个token值,移除则是通过token值来进行。插入和移除的过程就不看了,它正常消息的插入移除很相似,都需要在消息队列中寻找一个合适的位置进行插入。看看它在消息队列中生效的地方。依旧看next()方法

Message next() {

        // 省略部分代码

        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            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;
                if (msg != null && msg.target == null) {
                    // msg.target == null 就代表该msg是同步阻塞器。正常通过Handler发送的消息msg.target都不可能为空的。
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                    // 如果走到这里,则需要找一个异步的消息,Message的同步与异步的差别在这里就体现出来了,同步的消息会受阻塞器的影响,而异步消息不会。
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {// 这里的msg不可能是同步阻塞器。
                    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) {// 代表着得到的msg是异步消息
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                 // 省略部分代码

            }// end of synchronized (this)

            // 省略部分代码

        }
    }

这里我们要注意一点,同步阻塞器是无法阻塞在阻塞器生效前的同步消息。所以,当某个消息队列被阻塞器阻塞之后,要想执行操作,就需要你移除阻塞器或者发送异步消息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值