这周工作忙完了,闲来无事,去firebase看一眼,呃有个空指针:
Fatal Exception: java.lang.NullPointerException
Attempt to invoke virtual method 'void ***.verify.AuthDialogCallBack.onDismiss()' on a null object reference
赶紧打开代码敲敲,奇怪啊,照理说不应该出现这个空指针啊。。。。于是俺陷入了深深的思考。。
难道是内存泄漏???
脑子里突然闪出这个想法,凭我多年的经验,如果一些错误,找不到问题所在,很大的可能是内存泄漏导致的,那就查查吧。leakcanary走起~
果然有内存泄漏,可是内存泄漏为什么会导致此处的空指针异常呢?带着问题巡查代码。
原来是我的AuthVerifyDialogFragment实例,因为内存泄漏,导致没有回收掉,而我的AuthDialogCallBack已经回收掉了,所以导致了空指针的发生。
既然找到了问题所在,那就改起来吧。。。哎😔。
那么,问题来了,为什么会有这个内存泄漏的发生呢?
经过。。一番资料查询,原来是因为:
1、某一个 HandlerThread 的 Looper#loop 方法,一直等待 queue#next 方法返回,但是它的 msg 局部变量还引用着上一个循环中已经被放到 Message Pool 中 Message,我们称之为 MessageA。
2、DialogFragment#onActivityCreated 方法中,会调用 Dialog#setOnCancelListener 方法,将自身的引用作为 listener 参数传递给该方法
3、Dialog#setOnCancelListener 方法内部,会尝试从 Message Pool 中获取一个 Message,取出的 Message 刚好是 MessageA,然后将传入的 Listener 实例赋值给 MessageA#obj。
4、外部调用 cancel 的时候,Dialog 内部会将 MessageA 拷贝一份,我们称它为 MessageB,然后将 MessageB 发送到消息队列中。
5、DialogFragment 收到 onDestory 回调之后,LeakCanary 开始监听这个 DialogFragment 是否正常被回收,发现这个实例一直存在,dump 内存,分析引用链,报告内存泄漏问题。
感谢掘金作者:https://juejin.cn/post/6844904191912050702