当前位置: 首页 > news >正文

Handler中的IdleHandler

1.1 IdleHandler 基本情况

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

IdleHandler 位于 MessageQueue 类中的一个静态接口,如下:

MessageQueue#IdleHandler
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.
         */
         //返回true就是单次回调后不删除,下次进入空闲时继续回调该方法,false 只回调单次执行完之后会移除
        boolean queueIdle();
    }
    
   //判断当前队列是不是空闲的,辅助方法
   public boolean isIdle() {
        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            return mMessages == null || now < mMessages.when;
        }
    }

  //添加一个IdleHandler 到空闲队列中,ArrayList 存储
   public void addIdleHandler(@NonNull IdleHandler handler) {
        if (handler == null) {
            throw new NullPointerException("Can't add a null IdleHandler");
        }
        synchronized (this) {
            mIdleHandlers.add(handler);
        }
    }
	// 删除一个IdleHandler 
	public void removeIdleHandler(@NonNull IdleHandler handler) {
        synchronized (this) {
            mIdleHandlers.remove(handler);
        }
    }

	//message 的获取下一条消息
    Message next() {
        ...
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int 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)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                //表示没有设置idle handler 去运行,就阻塞
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }
				//设置长度,最小长度是4
                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 handler

                boolean keep = false;
                try {
                    //回调取出返回值
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }
				//这里看到了吧,如果是返回false, 那就进去了,执行操作后就从集合中remove了
                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }
		....
        }
    }
    ...
}
复制代码

1.2 使用场景

Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
                //这里做一些操作
                Log.i("xx","addIdleHandler invoked..."+iv.getWidth() + "::"+iv.getHeight());

                return false;
            }
});
复制代码

我记得之前我们想要获取xml中某个控件的widthheight 时,在 onCreate 方法中直接获取,会获取到是 0 , 因为这个 view 还未绘制完成,所以获取不到,当时的解决方案我记得是使用 Handler 发送一个延时消息获取,现在有更好的方式实现了,那就是通过 IdleHandler, 如上面代码所示。 当然还可以做一些其它预处理的简单操作。

IdleHandler 你明白了吗?欢迎大家留言讨论。

转载于:https://juejin.im/post/5c80b34351882564965ef821

相关文章:

  • 企业级 SpringBoot 教程 (十七)上传文件
  • bboss v5.5.3 发布,Elasticsearch Rest Client
  • 4.Git文件系统
  • ios监听键盘删除事件
  • 秒懂正则表达式
  • 怎么把GPU上训练的模型转到TPU或者CPU上去?DeepMind发布新工具支招
  • 互联网项目中mysql应该选什么事务隔离级别
  • 转载【阿里员工排查问题的工具清单,总有一款适合你】
  • 一、图书管理系统
  • 来自Google资深工程师的API设计最佳实践
  • grid布局基本概念
  • 论网站经营对一个企业的重要性
  • 持续交付基金会成立!Jenkins,Spinnaker等为首批捐赠项目
  • luogu P2634 [国家集训队]聪聪可可 点分治
  • link和@import的区别是什么 ?
  • (三)从jvm层面了解线程的启动和停止
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • Fabric架构演变之路
  • Java 23种设计模式 之单例模式 7种实现方式
  • JavaScript 一些 DOM 的知识点
  • javascript 总结(常用工具类的封装)
  • JS实现简单的MVC模式开发小游戏
  • leetcode386. Lexicographical Numbers
  • NSTimer学习笔记
  • Promise初体验
  • Spark RDD学习: aggregate函数
  • swift基础之_对象 实例方法 对象方法。
  • web标准化(下)
  • 从重复到重用
  • 翻译:Hystrix - How To Use
  • 关于 Cirru Editor 存储格式
  • 码农张的Bug人生 - 见面之礼
  • 世界上最简单的无等待算法(getAndIncrement)
  • 原生js练习题---第五课
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • ​configparser --- 配置文件解析器​
  • #laravel 通过手动安装依赖PHPExcel#
  • (003)SlickEdit Unity的补全
  • (1)(1.9) MSP (version 4.2)
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (2)STM32单片机上位机
  • (C)一些题4
  • (C++17) std算法之执行策略 execution
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (九十四)函数和二维数组
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (十六)一篇文章学会Java的常用API
  • (十一)手动添加用户和文件的特殊权限
  • (数据结构)顺序表的定义
  • (四) 虚拟摄像头vivi体验
  • (五)关系数据库标准语言SQL
  • (正则)提取页面里的img标签
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决