IdleHandler的使用

作者: 奔跑吧李博 | 来源:发表于2023-03-25 11:21 被阅读0次

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.
         */
        boolean queueIdle();
    }

Idlehandler是一个接口,IdleHandler 说白了,就是 Handler 机制提供的一种,可以在 Looper 事件循环的过程中,当出现空闲的时候,允许我们执行任务的一种机制。

它只有一个queueIdle方法,会在message queue处理完message后被调用。返回true会保留使用,返回false执行一次之后就会移除掉。

它是MessageQueue的内部接口,内部持有一个IdleHandler集合,可以进行添加和删除元素。

    private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();

    public void addIdleHandler(@NonNull IdleHandler handler) {
        if (handler == null) {
            throw new NullPointerException("Can't add a null IdleHandler");
        }
        synchronized (this) {
            mIdleHandlers.add(handler);
        }
    }

    public void removeIdleHandler(@NonNull IdleHandler handler) {
        synchronized (this) {
            mIdleHandlers.remove(handler);
        }
    }

MessageQueue 是一个基于消息触发时间的优先级队列,所以队列出现空闲存在两种场景:
MessageQueue 为空,没有消息;
MessageQueue 中最近需要处理的消息,是一个延迟消息(when>currentTime),需要滞后执行;

使用IdleHandler示例:

示例1:在activity的onCreate中做任务:

        Looper.myQueue().addIdleHandler {
            //做操作
            Log.i("minfo", "idleHandler excute")
            false
        }

示例2:延迟加载多个任务
在任务管理里加入多个task,addIdleHandler调用之后遍历task队列调用run方法。

public class DelayTaskDispatcher {
    private Queue<Task> delayTasks = new LinkedList<>();

    public DelayTaskDispatcher addTask(Task task) {
        delayTasks.add(task);
        return this;
    }

    private MessageQueue.IdleHandler idleHandler = () -> {
        if (delayTasks.size() > 0) {
            Task task = delayTasks.poll();
            if (task != null) {
                task.run();
            }
        }
        return !delayTasks.isEmpty();
    };

    public void start() {
        Looper.myQueue().addIdleHandler(idleHandler);
    }

    public interface Task extends Runnable {

    }

}

使用方式:

        DelayTaskDispatcher().addTask {
            Log.i("minfo", "excute task1")
            }.addTask {
            Log.i("minfo", "excute task2")
            }.addTask {
            Log.i("minfo", "excute task3")
        }.start()

打印结果:


关于IdleHandler问题

Q:IdleHandler 有什么用?

IdleHandler 是 Handler 提供的一种在消息队列空闲时,执行任务的时机;
当 MessageQueue 当前没有立即需要处理的消息时,会执行 IdleHandler;
Q:MessageQueue 提供了 add/remove IdleHandler 的方法,是否需要成对使用?

不是必须;
IdleHandler.queueIdle() 的返回值,可以移除加入 MessageQueue 的 IdleHandler;
Q:当 mIdleHanders 一直不为空时,为什么不会进入死循环?

只有在 pendingIdleHandlerCount 为 -1 时,才会尝试执行 mIdleHander;
pendingIdlehanderCount 在 next() 中初始时为 -1,执行一遍后被置为 0,所以不会重复执行;
Q:是否可以将一些不重要的启动服务,搬移到 IdleHandler 中去处理?

不建议;
IdleHandler 的处理时机不可控,如果 MessageQueue 一直有待处理的消息,那么 IdleHander 的执行时机会很靠后;
Q:IdleHandler 的 queueIdle() 运行在那个线程?

陷进问题,queueIdle() 运行的线程,只和当前 MessageQueue 的 Looper 所在的线程有关;
子线程一样可以构造 Looper,并添加 IdleHandler;

相关文章

网友评论

    本文标题:IdleHandler的使用

    本文链接:https://www.haomeiwen.com/subject/gwagrdtx.html