你知道android的MessageQueue.IdleHandler吗?

 

WeTest 导读java

干货!干货!或许能够是一种处理问题的新思路哟!android


 

前言数据库

咱们知道android是基于Looper消息循环的系统,咱们经过Handler向Looper包含的MessageQueue投递Message, 不过咱们常见的用法是这样吧?安全

 

 

通常咱们比较少接触MessageQueue, 其实它内部的IdleHandler接口有不少有趣的用法,首先看看它的定义:网络

 

 

简而言之,就是在looper里面的message暂时处理完了,这个时候会回调这个接口,返回false,那么就会移除它,返回true就会在下次message处理完了的时候继续回调,让咱们看看它有哪些有趣的用法吧~~多线程

 

1、提供一个android没有的声明周期回调时机架构

 若是有这种需求,想要在某个activity绘制完成去作一些事情,那这个时机是何时呢?有同窗可能以为onResume()是一个合适的机会,不是但是这个onResume() 真的是各类绘制都已经完成才回调的吗?No, too naive  ~~app

 

 

你看谷老师说了,onStart是用户可见,onResume是用户可交互,谷老师可没说onResume是绘制完成吧~那么android那些耗时的measure, layout, draw是在何时执行的呢?它们跟onResume()又有何关系呢?让咱们先来看看源码吧~框架

 

1. ActivityThread.java异步

咱们知道app的进程实际上是ActivityThread, 那么activity的生命周期天然是它来执行了,

 

 

 

performResumeActivity就是回调onResume了, 咱们继续看wm.addView方法, 这个ViewManager是一个接口,其实现者是WindowManagerImpl

 

2.WindowManagerImpl.java

 

 

这个mGlobal是WindowManagerGlobal对象,咱们继续

 

3.WindowManagerGlobal.java

 

 

这里咱们new 出了ViewRootImpl对象, 咱们知道这个对象就是android view的根对象了,负责view绘制的measure, layout, draw的巨长的方法 performTraversals就是这个类的,咱们继续看setView方法

 

4.ViewRootImpl.java

 

 

这个函数调用了关键方法requestLayout(),  咱们继续跟踪,顺便说下,后面一连串的BadTokenException就是咱们经常遇到的dialog相关抛出的,也有些特殊场景也会出这个异常,能够到这里查看线索。

 

 

 调用了scheduleTraversals, 从名字就能看出来了吧:

 

 

它往Choreographer里面post了一个runnable, 这个Choreographer是android负责帧率刷新相关的东西,咱们暂时能够不关注它,能够理解为往主线程post一个消息是同样的,顺便说下这个Choreographer能够作帧率检测相关的东西,,能够用于卡顿检测什么的···

 

 

 咱们看这个runnable果真是去执行了那个巨长无比的函数performTraversals函数,  如今咱们能够总结下流程了:

 

 

 

结论:因此若是咱们想在界面绘制出来后作点什么,那么在onResume里面显然是不合适的,它先于measure等流程了 有人可能会说在onResume里面post一个runnable能够吗?仍是不行,由于那样就会变成这个样子

 

因此你的行为同样会在绘制以前执行,这个时候咱们的主角IdleHandler就发挥做用了,咱们前面说了,它是在looper里面message暂时执行完毕了就会回调,顾名思义嘛,Idle就是队列为空的意思,那么咱们的onResume和measure, layout, draw都是一个个message的话,这个IdleHandler就提供了一个它们都执行完毕的回调了,大概就是这样

 

 

说了这么多,那么如今获取到这个时机有什么用呢? look!!

 

 

这个是咱们地图的公交详情页面, 进入以后产品要求左边的页卡须要展现,能够看到左边的页卡是一个很是复杂的布局,那么进入以后的效果能够明显看到头部的展现信息是先显示空白再100毫秒左右以后才展现出来的,缘由就是这个页卡的内容比较复杂,用数据向它填充的时候花了较长时间,代码以下:

 

 

能够看到这个detailView就是这个侧滑的页卡了,填充里面的数据花了90ms,若是这个时间是用在了界面view绘制以前的话,就会出现以上的效果了,view先是白的,再出现,这样就体验很差了,若是咱们把它放到IdleHandler里面呢?代码以下:

 

 

效果是这样的:

 

 

看出不一样了吗?顶部的页卡先展现出来了,这样体验是否是会更好一些呢。虽然只有短短90ms,不过咱们作app也应该关注这种细节优化的,是吧~ 这个作法也提供了一种思路,android自己提供的activity框架和fragment框架并无提供绘制完成的回调,若是咱们本身实现一个框架,就可使用这个IdleHandler来实现一个onRenderFinished这种回调了。

 

2、能够结合HandlerThread, 用于单线程消息通知器

咱们先思考一个问题,若是有一个model数据管理模块,怎么设计?好比地图的收藏模块的model部分。就是下面这个图的小星星:

 

 

它原来的model设计大概是这个样子的:

 

 

 因为这个model是单例的,并且是多线程能够访问的,因此它的增删改查都加上了锁,并且因为外部访问须要遍历有哪些收藏点,因此外部遍历列表也须要加锁,大概是这样的:

 

 

 由于是多线程可访问的,若是遍历不加锁的话,其余线程删除了一个收藏,就会crash的,原来的这样设计有几个很差的地方:

1. 外部使用者须要关系锁的使用,增长了负担,不用还不安全

2. 若是在主线程加锁的话,可能另外一个线程执行操做会阻塞主线程形成anr

 

总之,多线程代码就是容易出错,并且真的出错的时候查起来太费劲了,目前收藏夹模块就有N多bug,因此我想用单线程来解决这个问题,因为model层的访问须要数据库和网络等,因此须要异步线程,那么单线程队列+异步线程,首先想到的就是HandlerThread, 大概架构以下:

 

 

 如今,咱们把原来多线程的逻辑改到了单线程里面,各类收藏的model共用一个HandlerThread,这样咱们增删改查都不用加锁了,出错概率大大减少,并且这种model的设计有点相似插件的意思,能够很方便的增长其余收藏。

 

Ok, 那么跟咱们的主题IdleHandler有什么关系呢?思考这样一个问题,地图上的小星星须要实时更新,也就是model的任何变化都须要显示到地图上,那么收藏的小星星就应该做为model的观察者,之前的作法是向收藏model注册监听,在每个增删改查操做后都对观察者回调,大概是这样:

 

 

这样有一个小小的问题,就是若是有一个操做生成10个快速连续的增删改查操做,那么咱们的UI就会收到10次回调,而这种场景下咱们其实只须要最后一次回调就够了,中间操做其实不用刷新UI的。

 

那么如今改为单线程模型,咱们又该如何处理这个问题呢?固然咱们也能在每一个post到异步线程的runnable里面去回调观察者,但这样未免不够优雅,因此这个时候IdleHandler不就又能够发挥做用了吗?它是在消息暂时处理完的时候回调的呀,不是很符合咱们的时机么,对吧?

 

就是这个样子了,这里为何不用第一个场景下的Looper.myQueue().addIdleHandler()呢?注意这个地方Looper.myQueue()若是在主线程调用就会使用主线程looper了,因此我选择反射这个HandlerThread的looper来设置它,这个IdleHandler咱们返回了true, 表示咱们要长期监听消息队列,由于返回false,下次就没有回调了哦。

 

好了,结论是这个地方IdleHandler用做了一个消息的触发器,是否是挺有意思的呢?

 

3、 结语

 若是你没有用过它,从今天开始试试吧,这篇文章只是我我的的一点小思路,说不定这个IdleHandler有不少其余的用法呢~~

 

腾讯WeTest提供上千台真实手机,随时随地进行测试,保障应用/手游品质。节省百万硬件费用,加速敏捷研发流程。

 

同时腾讯WeTest兼容性测试团队积累了10年的手游测试经验,旨在经过制定针对性的测试方案,精准选取目标机型,执行专业、完整的测试用例,来提早发现游戏版本的兼容性问题,针对性地作出修正和优化,来保障手游产品的质量。目前该团队已经支持全部腾讯在研和运营的手游项目。

 

欢迎进入:http://wetest.qq.com/product/cloudphone 体验安卓真机

欢迎进入:http://wetest.qq.com/product/expert-compatibility-testing 使用专家兼容测试服务。WeTest兼容性测试团队期待与您交流!You Create,We Test!

 

若是对使用当中有任何疑问,欢迎联系腾讯WeTest企业QQ:800024531

相关文章
相关标签/搜索