• 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);
                        }
                    }
                }
                ......
            }
        }
    }
  • 相关阅读:
    NOIP 2016 回文日期
    USACO Ski Course Design
    USACO Combination Lock
    USACO 利润Profits
    POJ 3368 Frequent values
    USACO Balanced Lineup
    JDOJ 1065 打倒苏联修正主义
    JDOJ 2174 忠诚
    VIJOS-P1514 天才的记忆
    VIJOS-P1423 最佳路线
  • 原文地址:https://www.cnblogs.com/lianzhen/p/12927013.html
Copyright © 2020-2023  润新知