百色住房和城乡建设部网站国涟建设集团有限公司网站
- 作者: 五速梦信息网
- 时间: 2026年03月21日 10:04
当前位置: 首页 > news >正文
百色住房和城乡建设部网站,国涟建设集团有限公司网站,网站到期后如何转域名,店面怎么做位置定位前言 关于IdleHandler#xff0c;比较多同学错误地认为#xff0c;这个Handler的作用是主线程空闲状态时才执行它#xff0c;那么用它做一些耗时操作也没所谓。可是IdleHandler在主线程的MessageQueue中#xff0c;执行queueIdle()默认当然也是执行在主线程中的#xff0…前言 关于IdleHandler比较多同学错误地认为这个Handler的作用是主线程空闲状态时才执行它那么用它做一些耗时操作也没所谓。可是IdleHandler在主线程的MessageQueue中执行queueIdle()默认当然也是执行在主线程中的这里的耗时操作其实很容易引起卡顿和ANR。 IdleHandler的介绍 IdleHandler是一种在只有当消息队列没有消息时或者是队列中的消息还没有到执行时间时才会执行的IdleHandler。从源码上看IdleHandler是一个回调接口当线程中的消息队列将要阻塞等待消息的时候就会回调该接口也就是说消息队列中的消息都处理完毕了没有新的消息了处于空闲状态时就会回调该接口。 public static interface IdleHandler {boolean queueIdle(); }IdleHandler的使用 IdleHandler是MessageQueue的静态内部接口通过静态方法就能拿得到不过要注意的事当前Looper是主线程的Looper的话取到的也是主线程的MessageQueue Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {Overridepublic boolean queueIdle() {//空闲时处理逻辑return false;} });IdleHandler的问题 IdleHandler如果是主线程的执行超过5s同样也是会报ANR我们通过主线程模拟休眠会发现App直接ANR Looper.myQueue().addIdleHandler(object : MessageQueue.IdleHandler {override fun queueIdle(): Boolean {Log.e(TAG, [queueIdle] sleep(5000) start)Thread.sleep(5000)Log.e(TAG, [queueIdle] sleep(5000) end)return false} })IdleHandler的监控分析 为了防止IdleHandler滥用监控起来也是很有必要特别是第三方产商经常通过这个接口做一些耗时操作。通过查看源码找到IdleHandler的Hook点 通过Looper.myQueue().addIdleHandler()开始可以看到是每次通过mIdleHandlers加入到队列中 public void addIdleHandler(NonNull IdleHandler handler) {if (handler null) {throw new NullPointerException(Cant add a null IdleHandler);}synchronized (this) {mIdleHandlers.add(handler);} }mIdleHandlers是一个列表会保存每一个添加进来的IdleHandler private final ArrayListIdleHandler mIdleHandlers new ArrayListIdleHandler();在Message#next()中执行完Handler消息空闲后会将当前的IdleHandler列表循环遍历执行queueIdle() Message next() {…..for (;;) {…..if (mPendingIdleHandlers null) {mPendingIdleHandlers new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];}// 1、取出所有IdleHandlermPendingIdleHandlers mIdleHandlers.toArray(mPendingIdleHandlers);for (int i 0; i pendingIdleHandlerCount; i) {final IdleHandler idler mPendingIdleHandlers[i];mPendingIdleHandlers[i] null; // release the reference to the handlerboolean keep false;try {// 2、执行IdleHandler的queueIdle()keep idler.queueIdle();} catch (Throwable t) {Log.wtf(TAG, IdleHandler threw exception, t);}if (!keep) {synchronized (this) {mIdleHandlers.remove(idler);}}}} }IdleHandler的监控实现 从IdleHandler的执行流程可以看出Hook点就在mIdleHandlers列表中将当前的MessageQueue中的mIdleHandlers列表替换成自己的列表 class IdleHandlerMonitor {private HandlerThread idleHandlerThread;private Handler idleHandlerHandler;private static String mIdleHandler null;IdleHandlerMonitor() {// 1、创建子线程的handleridleHandlerHandler方便后续在子线程发送消息不被主线程卡住影响if (Build.VERSION.SDK_INT 23) {this.idleHandlerThread new HandlerThread(IdleHandlerThread);this.idleHandlerThread.start();this.idleHandlerHandler new Handler(this.idleHandlerThread.getLooper());this.detectIdleHandler();}}RequiresApi(api 23)private void detectIdleHandler() {// 2、修改MessageQueue中的mIdleHandlers变量传入自定义的Listtry {MessageQueue mainQueue Looper.getMainLooper().getQueue();Field field MessageQueue.class.getDeclaredField(mIdleHandlers);field.setAccessible(true);CustomArrayListMessageQueue.IdleHandler myIdleHandlerArrayList new CustomArrayList();field.set(mainQueue, myIdleHandlerArrayList);} catch (Throwable var4) {var4.printStackTrace();}}private class CustomArrayListT extends ArrayList {public boolean add(Object o) {if (o instanceof MessageQueue.IdleHandler) {// 3、将原来的IdleHandler包装进自己的CustomIdleHandlerCustomIdleHandler customIdleHandler new CustomIdleHandler((MessageQueue.IdleHandler) o);return super.add(customIdleHandler);}return super.add(o);}public boolean remove(Nullable Object o) {if (o instanceof CustomIdleHandler) {return super.remove(((CustomIdleHandler) o));}return super.remove(o);}}private class CustomIdleHandler implements MessageQueue.IdleHandler {private MessageQueue.IdleHandler idleHandler;CustomIdleHandler(MessageQueue.IdleHandler idleHandler) {this.idleHandler idleHandler;}Overridepublic boolean queueIdle() {mIdleHandler this.idleHandler.toString();idleHandlerHandler.removeCallbacks(idleHanlderRunnable);idleHandlerHandler.postDelayed(idleHanlderRunnable, 3000L);// 4、将包装起来的IdleHandler取出来执行queueIdle包装前设置多一项3s的延时任务。// 只要queueIdle在3s内没执行完将执行当前的idleHanlderRunnableboolean ret this.idleHandler.queueIdle();idleHandlerHandler.removeCallbacks(idleHanlderRunnable);return ret;}}// 5、报告输出当前Idle信息超时通知private static Runnable idleHanlderRunnable () - {Log.e(TAG, [queueIdle] more then 3000L \n message mIdleHandler);}; }hook的巧妙点在于将当前的List换成自己的List然后在List的添加和删除中偷梁换柱成自己的IdleHandler进行加工处理 IdleHandler的验证 Hook解决完之后我们来通过Demo验证下是否是我们想要的监控通过初始化IdleHandlerMonitor()启动监控然后模拟3次IdleHandler发送不同时间的消息最后看日志输出是否被捕获到超时的Idle任务 private fun initIdelHandler() {IdleHandlerMonitor()Looper.myQueue().addIdleHandler(object : MessageQueue.IdleHandler {override fun queueIdle(): Boolean {Log.e(TAG, [queueIdle] sleep(2000) start)Thread.sleep(2000)Log.e(TAG, [queueIdle] sleep(2000) end)return false}})Looper.myQueue().addIdleHandler(object : MessageQueue.IdleHandler {override fun queueIdle(): Boolean {Log.e(TAG, [queueIdle] sleep(5000) start)Thread.sleep(5000)Log.e(TAG, [queueIdle] sleep(5000) end)return false}})Looper.myQueue().addIdleHandler(object : MessageQueue.IdleHandler {override fun queueIdle(): Boolean {Log.e(TAG, [queueIdle] sleep(10000) start)Thread.sleep(10000)Log.e(TAG, [queueIdle] sleep(10000) end)return false}}) }通过日志输出结果可以看到当前的Idle阻塞3s时候的代码类位置 E/TAG: [queueIdle] sleep(2000) start E/TAG: [queueIdle] sleep(2000) end E/TAG: [queueIdle] sleep(5000) start E/TAG: [queueIdle] more then 3000L messagecom.example.syncbarriermonitor.MainActivity\(initIdelHandler\)24d9ab66 E/TAG: [queueIdle] sleep(5000) end E/TAG: [queueIdle] sleep(10000) start E/TAG: [queueIdle] more then 3000L messagecom.example.syncbarriermonitor.MainActivity\(initIdelHandler\)3be7cc0
- 上一篇: 百科网站源码佛山怎么做网站
- 下一篇: 佰汇康网站建设做海外市场什么网站推广
相关文章
-
百科网站源码佛山怎么做网站
百科网站源码佛山怎么做网站
- 技术栈
- 2026年03月21日
-
百度做网站哪里可以学装潢设计图片三室效果图
百度做网站哪里可以学装潢设计图片三室效果图
- 技术栈
- 2026年03月21日
-
百度做网站吗天津企业展厅设计公司
百度做网站吗天津企业展厅设计公司
- 技术栈
- 2026年03月21日
-
佰汇康网站建设做海外市场什么网站推广
佰汇康网站建设做海外市场什么网站推广
- 技术栈
- 2026年03月21日
-
班级网站设计模板wordpress 程序更新
班级网站设计模板wordpress 程序更新
- 技术栈
- 2026年03月21日
-
搬瓦工做网站优化建站
搬瓦工做网站优化建站
- 技术栈
- 2026年03月21日






