背景
最近接手新项目,遇到了一个跟 Handler 有关的 Bug,在解决过程中耗费了挺多时间的,最后通过另外的思路解决了。
在此通过本篇文章分享给大家,也为大家后面遇到 Handler 相关问题时能快速定位解决。
问题描述
问题点在于 Handler 发送的消息没有在 handleMessage 收到。
当然发送消息的地方和接受消息的地方不是同一个文件。
可以认为 Handler 通过 HashMap 统一管理起来。
思路 1
会不会发送的 Handler 跟接收的 Handler 不是同一个?
毕竟是通过 HashMap 管理,有可能被替换了?
验证方法:打印一下 Handler 的引用就可以确认,结果是同一个 Handler。
思路 2
会不会发送的消息被 remove 掉了?
验证方法:通过新引入一个唯一的 msg.what 来确认,结果也没有收到。
思路 3
/**
* Sends a Message containing only the what value.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
通过源码的注释,发现消息如果已经在队列,是不会再塞进去的,但是如果队列已经存在,也不应该收不到啊。
最后打印返回值也是正确的。
虽然这个思路没有解决问题,但是由于这个,打开了另一个思路,那就是会不会队列阻塞了,消息卡住了?
最终验证方法
因此最终通过引入 IdleHandler 来验证到底消息队列是不是出问题了,没有空闲消息回调。
关于 IdleHandler,我简单说明下,一般是在 Handler 空闲时会回调,如果你监听后没有移除,会一直回调。
用法之一是延迟初始化,提高界面渲染速度。
更多资料见:
最终确认了,在这个发送消息的线程(子线程)里面使用 IdleHandler 没有回调,而原先的 Handler 是在主线程构建的。
因此根源是由于修改了 Handler 的线程,而所在的子线程消息不断的产生消息造成队列可能一直被占用,因此新发的消息收不到。
随着Android开发行业逐渐饱和,对Android开发者的面试要求也越来越高,是否掌握底层源码,便是考验一名Android开发者的重要一环。面试被问到源码问题答不出来,会掉身价、砍薪资尚且不谈,甚至连面试都过不了!
网上各类源码解析的文章博客五花八门、良莠不齐。杂乱、要么内容质量太浅,零散、碎片化,总看着看着就衔接不上了。
这里最后分享耗时一年多整理的一系列Android学习资源:Android源码解析、Android第三方库源码笔记、Android进阶架构师七大专题学习、历年BAT面试题解析包、Android大佬学习笔记等等,这些内容均免费分享给大家,需要完整版的朋友,点这里可以看到全部内容