由Hander 引起的Activity内存泄露

首先 内部类会持有外部类的引用 ,我们先记住这条,这是这个问题的根本原因
我们看三种在activity内使用handler 的方式
一 直接创建handler对象
二 直接创建Handler 对象并复写onHandleMessage()方法
三 自定义内部类MyHandler 并创建对象

由Hander 引起的Activity内存泄露_第1张图片
image.png

可以看到 编译器有警告提示了,但是 只有handler2 提示了有内存泄露风险
handler3 提示的是内部类需要使用static
我们再看 .dex 文件 这样声明以后 代码的结构

由Hander 引起的Activity内存泄露_第2张图片
image.png

可以看到 有一个匿名内部类 MainActivity MyHandler

开头的第一句话,内部类会持有外部实例引用
所以 你懂得
handle2 当前警告的原因是因为,编译器知道,这种要复写的方法会创建匿名内部类来持有activity,所以给你警告了,
最终 activityThread -> looper -> messageQueue ->handler -> 匿名内部类 ->activity

MyHandler 的引用路径 activityThread ->Looper ->messageQueue ->MyHandler -> activity

目前handler1 没有问题
接下来我们在用handler时 通常会有 handler.post(Runnable )方法

由Hander 引起的Activity内存泄露_第3张图片
image.png

可以看到 .dex文件中 又多了一个 匿名内部类MainActivity$2 看他的方法就是我们新创建的 new Runnable{} 同样 持有MainActivity实例的引用

所以这么来看 真正造成内存泄露的 其实是
1、由于复写onHandleMessage 方法而生成的匿名内部类
2、创建 接口对象runnable 时 生成的匿名内部类
3、自定义的内部类
(我返回去看了眼第一行...)

彩蛋: 基于以上结果 推断
1、在某个类内 改变其他类的实现时 会产生匿名内部类 如上面的 复写onHandleMessage 以及创建 Runnable 实例 ,相当于 你在原有定义好的类 增加了关于当前类的各种操作,造成需要创建一个代理来实现,直接创建对象不改变其实现则不会创建匿名类代理,参考handler1的声明方式

你可能感兴趣的:(由Hander 引起的Activity内存泄露)