zoukankan      html  css  js  c++  java
  • Android IdleHandler 原理浅析

    问:什么是 IdleHandler?有什么用?怎么用?

    答:IdleHandler 可以用来提升性能,主要用在我们希望能够在当前线程消息队列空闲时做些事情(譬如 UI 线程在显示完成后,如果线程空闲我们就可以提前准备其他内容)的情况下,不过最好不要做耗时操作。具体用法如下。

    //getMainLooper().myQueue()或者Looper.myQueue()
    Looper.myQueue().addIdleHandler(new IdleHandler() {  
        @Override  
        public boolean queueIdle() {  
            //你要处理的事情
            return false;    
        }  
    });

    关于 IdleHandler 在 MessageQueue 与 Looper 和 Handler 的关系原理源码分析如下

    /**
     * 获取当前线程队列使用Looper.myQueue(),获取主线程队列可用getMainLooper().myQueue()
     */
    public final class MessageQueue {
        ......
        /**
         * 当前队列将进入阻塞等待消息时调用该接口回调,即队列空闲
         */
        public static interface IdleHandler {
            /**
             * 返回true就是单次回调后不删除,下次进入空闲时继续回调该方法,false只回调单次。
             */
            boolean queueIdle();
        }
    
        /**
         * <p>This method is safe to call from any thread.
         * 判断当前队列是不是空闲的,辅助方法
         */
        public boolean isIdle() {
            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                return mMessages == null || now < mMessages.when;
            }
        }
    
        /**
         * <p>This method is safe to call from any thread.
         * 添加一个IdleHandler到队列,如果IdleHandler接口方法返回false则执行完会自动删除,
         * 否则需要手动removeIdleHandler。
         */
        public void addIdleHandler(@NonNull IdleHandler handler) {
            if (handler == null) {
                throw new NullPointerException("Can't add a null IdleHandler");
            }
            synchronized (this) {
                mIdleHandlers.add(handler);
            }
        }
    
        /**
         * <p>This method is safe to call from any thread.
         * 删除一个之前添加的 IdleHandler。
         */
        public void removeIdleHandler(@NonNull IdleHandler handler) {
            synchronized (this) {
                mIdleHandlers.remove(handler);
            }
        }
        ......
        //Looper的prepare()方法会通过ThreadLocal准备当前线程的MessageQueue实例,
        //然后在loop()方法中死循环调用当前队列的next()方法获取Message。
        Message next() {
            ......
            for (;;) {
                ......
                nativePollOnce(ptr, nextPollTimeoutMillis);
                synchronized (this) {
                    ......
                    //把通过addIdleHandler添加的IdleHandler转成数组存起来在mPendingIdleHandlers中
                    // 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);
                }
    
                // Run the idle handlers.
                // We only ever reach this code block during the first iteration.
                //循环遍历所有IdleHandler
                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 {
                        //调用IdleHandler接口的queueIdle方法并获取返回值。
                        keep = idler.queueIdle();
                    } catch (Throwable t) {
                        Log.wtf(TAG, "IdleHandler threw exception", t);
                    }
                    //如果IdleHandler接口的queueIdle方法返回false说明只执行一次需要删除。
                    if (!keep) {
                        synchronized (this) {
                            mIdleHandlers.remove(idler);
                        }
                    }
                }
                ......
            }
        }
    }
  • 相关阅读:
    java通过LinkedList实现堆栈和队列数据结构
    华硕笔记本无法调节屏幕亮度
    Java8新特性
    GitLab使用记录
    Java IO流关闭问题之原理简析
    gradle build docker image
    mysql安装及使用
    前端div层级控制
    Could not get dialect instance.
    Starting a Gradle Daemon, 5 busy and 1 incompatible and 1 stopped Daemons could not be reused, use --status for details FAILURE: Build failed with an exception. * What went wrong: Could not dispatch
  • 原文地址:https://www.cnblogs.com/lianzhen/p/12927013.html
Copyright © 2011-2022 走看看