原因
页面退出时,post到handler的runnable是延迟任务,还未到时延,且作为非静态内部匿名类,持有了外部TvTaobaoImp的强引用,而TvTaobaoImp持有着Activity的context,导致Activity没有被回收。
分析
可以用LeakCannry检测是否存在内存泄漏,如果存在,会出警告,并给出提示信息。作者君这里直接分析了dump下来的堆转储文件。
TvTaoBaoImp对象持有callBack,这是个runnable,非静态内部类,支持TvTaoBaoImp,它被post到MessageQuene队列中,Looper会循环去取里头的Message处理,页面退出时,该Message尚未被处理。于是一级级被持有,最终导致Activity也无法被释放。
image.png image.png
找到泄露的地方,解决方案就非常简单了:
1.handler作为内部静态类,以软引用的方式持有外部对象。
2.由于逻辑上本身在页面退出后不需要再执行延时里的业务代码,因此在页面退出后,清空handler的message和runnable。
小结
使用延迟消息需要谨慎,注意页面退出是否该消息还需要执行,若需要可以使用软引用,若不需要则将消息从队列中移除。
有时候泄漏的本质,就是彼此生命周期不一样了,一方结束,另一方还未结束,不能一上来都用弱引用,引用类型各有其存在的合理性,各有优缺点。作者君的业务场景,实则是二者的生命周期不一致,页面消失时,runnable也不应该再执行。
网友评论