时隔很久,重温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)            // 省略部分代码        }    }

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

更多相关文章

  1. Handler,Looper,MessageQueue的实现
  2. Android(安卓)线程同步 ConditionVariable的用法
  3. Android的状态栏通知(Notification)
  4. Version Code 版本设置
  5. Android聊天室(源码)
  6. Android(安卓)蓝牙(BLE)连接,发送,接收消息
  7. Android(安卓)MQTT
  8. Android(安卓)MediaPlayer 字幕同步
  9. Android(安卓)Camera 数据流

随机推荐

  1. 快速排序就这么简单
  2. PMP学习之49个子过程俚语版理解与速记
  3. 移动商城项目总结
  4. pgsql 修改字段类型为json
  5. Android:shape设置corners(圆角)不能正常显
  6. Elasticsearch就是这么简单
  7. NacosSync多集群迁移
  8. 递归就这么简单
  9. 学了这么久java反射,你知道class.forName
  10. 华为HMS Core音频服务,让有声世界更动听