IdleHandler的使用及原理

源码 2024-10-2 11:22:07 94 0 来自 中国
IdleHandler方式就是利用其特性,只有CPU空闲的时候才会执行相关任务,并且我们可以分批进行任务初始化,可以有效缓解界面的卡顿。
简单用法代码如下:
        Looper.myQueue().addIdleHandler(object: MessageQueue.IdleHandler {            override fun queueIdle(): Boolean {                //执行任务                return false;            }        })可以将上述代码添加到Activity onCreate中,在queueIdle()方法中实现延迟执行任务,在主线程空闲,也就是activity创建完成之后,它会执行queueIdle()方法中的代码。
如何设置是否重复执行

queueIdle()返回true表示可以反复执行该方法,即执行后还可以再次执行;返回false表示执行完该方法后会移除该IdleHandler,即只执行一次。
IdleHandler源码解析:

IdleHandler属于MessageQueue内部接口,只有一个queueIdle()方法声明。通过方法addIdleHandler将我们的idleHandler添加到集合中。
public final class MessageQueue {    private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();        /**     * 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);        }    }      /**     * Callback interface for discovering when a thread is going to block     * waiting for more messages.     */    public static interface IdleHandler {        boolean queueIdle();    }}IdleHandler的queueIdle方法何时执行

在MessageQueue取消息的next方法中,IdleHandler相关代码如下:
    @UnsupportedAppUsage    Message next() {        ...        int pendingIdleHandlerCount = -1; // -1 only during first iteration        int nextPollTimeoutMillis = 0;        for (;;) {            if (nextPollTimeoutMillis != 0) {                Binder.flushPendingCommands();            }            nativePollOnce(ptr, nextPollTimeoutMillis);            synchronized (this) {                ...                if (msg != 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)) {                   //如果消息队列为空或者消息执行时间还未到,则获取IdleHandler队列的大小,下面需要用到                    pendingIdleHandlerCount = mIdleHandlers.size();                }                if (pendingIdleHandlerCount <= 0) {                    // No idle handlers to run.  Loop and wait some more.                   //无需要执行的  idle handler,则继续阻塞                    mBlocked = true;                    continue;                }                if (mPendingIdleHandlers == null) {                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];                }                //将IdleHandler列表转为数组                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;                mPendingIdleHandlers = null; // release the reference to the handler                boolean keep = false;                try {                    keep = idler.queueIdle();   //开始顺序执行所有IdleHandler的queueIdle方法                } catch (Throwable t) {                    Log.wtf(TAG, "IdleHandler threw exception", t);                }                if (!keep) {   //如果发现有queueIdle()方法返回false,则线程安全地删除这个idlehandler不再执行queueIdle                    synchronized (this) {                        mIdleHandlers.remove(idler);                    }                }            }            ...        }    }多任务延迟初始化实战:

我们根据queueIdle返回true时可以执行多次的特点,可以实现一个任务列表,然后从这个任务列表中取任务执行。
public class TaskDispatcher {    private Queue<Runnable> delayTasks = new LinkedList<>();    private MessageQueue.IdleHandler idleHandler = () -> {        if (delayTasks.size() > 0) {            Runnable task = delayTasks.poll();            if (task != null) {                task.run();            }        }        return !delayTasks.isEmpty();  //只要task任务不为空,就继续执行初始化    };    public TaskDispatcher addTask(Runnable task) {        delayTasks.add(task);        return this;    }    public void start() {        Looper.myQueue().addIdleHandler(idleHandler);    }}创建一个ARouter初始化和Webview初始的task
public class WebviewInitTask implements Runnable {    @Override    public void run() {        Log.i("minfo", "初始化Okhttp");    }}public class WebviewInitTask implements Runnable {    @Override    public void run() {        Log.i("minfo", "初始化Webview");    }}界面显示后进行调用:
override fun onCreate(savedInstanceState: Bundle?) {        setTheme(R.style.AppTheme)        super.onCreate(savedInstanceState)                    TaskDispatcher()            .addTask(ARouterInitTask())            .addTask(WebviewInitTask())            .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;
参考:
https://juejin.cn/post/7055564669540368392
Github代码地址:

https://github.com/running-libo/PerformanceOpt
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-23 19:20, Processed in 0.169225 second(s), 32 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表