【Android 异步操作】Handler 机制 ( MessageQueue 空闲任务 IdleHandler 机制 )
文章目录
- 一、MessageQueue 空闲任务 IdleHandler 机制
- 二、MessageQueue 中空闲任务 IdleHandler 相关源码
一、MessageQueue 空闲任务 IdleHandler 机制
在 消息队列 MessageQueue 的 next 获取下一条消息的方法中 ,
在循环获取消息的最后有如下代码 :
public final class MessageQueue {@UnsupportedAppUsageMessage next() {// ...// 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)) {// 如果取出的 消息为空 , 就会执行 IdleHandlerpendingIdleHandlerCount = 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);// ...} }开始判定 pendingIdleHandlerCount 大小 , 如果小于 000 则执行后续 与 IdleHandler 相关操作 ;
IdleHandler 是一个 接口 , 代码如下 :
public final class MessageQueue {/*** 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.*/boolean queueIdle();} }在上述如果取出的 mMessage 消息为空 mMessages == null , 则执行 IdleHandler ;
IdleHandler 使用时 , 调用 addIdleHandler 函数 , 该函数会将 IdleHandler 加入到 mIdleHandlers 集合中 ,
MessageQueue 消息队列 addIdleHandler 函数如下 :
public final class MessageQueue {/*** Add a new {@link IdleHandler} to this message queue. This may be* removed automatically for you by returning false from* {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is* invoked, or explicitly removing it with {@link #removeIdleHandler}.** <p>This method is safe to call from any thread.** @param handler The IdleHandler to be added.*/public void addIdleHandler(@NonNull IdleHandler handler) {if (handler == null) {throw new NullPointerException("Can't add a null IdleHandler");}synchronized (this) {mIdleHandlers.add(handler);}} }在 MessageQueue 的 next 方法中继续向下执行 , 开始遍历 mIdleHandlers 集合 , 先将集合 mIdleHandlers 转为 mPendingIdleHandlers 数组 , 然后遍历该数组 ,
遍历时 , 调用 IdleHandler 对象的 queueIdle 方法 ,
如果上面的 queueIdle 方法返回值是 false , 就会从 mIdleHandlers 集合中 移除该元素 ,
如果上面的 queueIdle 方法返回值是 true , 那么下一次再次执行到这里时 , 还会 继续回调该函数 ;
上述操作对应的 MessageQueue 的 next 方法内的部分源码 :
public final class MessageQueue {@UnsupportedAppUsageMessage next() {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 handlerboolean 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;} }IdleHandler 的作用是 , 当消息队列 MessageQueue 中没有消息处理时 , 处于闲置状态时 , 此时就会回调一次用户注册的 IdleHandler ,
如果该 IdleHandler 的 queueIdle 方法返回 false , 那么该 IdleHandler 只会 执行一次 ,
如果该 IdleHandler 的 queueIdle 方法返回 true , 则 每次空闲 , 都要执行一次该 IdleHandler ;
二、MessageQueue 中空闲任务 IdleHandler 相关源码
public final class MessageQueue {@UnsupportedAppUsageMessage mMessages;@UnsupportedAppUsageprivate final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();private IdleHandler[] mPendingIdleHandlers;@UnsupportedAppUsageMessage 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;if (ptr == 0) {return null;}int pendingIdleHandlerCount = -1; // -1 only during first iterationint nextPollTimeoutMillis = 0;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) {// 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();return msg;}} else {// No more messages.nextPollTimeoutMillis = -1;}// 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)) {// 如果取出的 消息为空 , 就会执行 IdleHandlerpendingIdleHandlerCount = 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 handlerboolean 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;}}/*** 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.*/boolean queueIdle();}}
总结
以上是生活随笔为你收集整理的【Android 异步操作】Handler 机制 ( MessageQueue 空闲任务 IdleHandler 机制 )的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 【Android 异步操作】Handle
- 下一篇: 【Android 异步操作】Handle