为什么? 首先我们需要知道一下知识点: 不要认为Java会为你清理runningthread。在上面的例子中,我们会很容易的就想象当用户离开这个Activity的时候,Activity实例会被垃圾回收器回收,所有在这个Activity中开启的running thread也会被清理掉。事实上不是这样的。Java线程将会一直存在,直到他们被显示的关闭或者处理结束,或者被杀掉整个进程。
那么面对这样的问题 我们该如何解决呢? 先看一个简单的栗子: 框出来的部分已经犯法了,那我们如何解决呢?1.给一个标志位,如果activity 被销毁后,不需要Thread中继续操作 那个我们可以给出一个标志位;
2.在onDestroy中直接调用thread.join();对于HandlerThread应调用 thread.getLooper().quit();
解决方法先讲到这里,当大家看到第一个图的时候,明眼人是不是已经看出来另外一个内存泄漏的问题。是什么呢?大写的Handler.为什么?
在这里我们再来复习一下java基础:非静态内部类和静态内部类的区别之一:是否拥有指向外部类对象的引用。非静态内部类:可以访问创建它得外部类对象的全部内容,甚至包括私有,要想实现这个,内部类的对象就必须有指向外部类对象的引用。Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去,并一直保存着。这样就使得内部类对象始终可以访问其外部对象,同时这也是在外部类作用范围之外创建内部类对象时必须先创建其外部类对象的原因。
那么回到图一就会发现handler 是一个非静态的内部类,如果我们要在这个activity的作用范围外使用,那么它将始终持有activity的引用,造成内存不能释放,导致内存泄漏。需要注意的是泄露同样发生在匿名的runnable类中,非静态的匿名类也保持了一个对外部的引用,也会导致context 泄露。
要解决以上问题方法一:
因为 静态内部类 不持有外部类的引用。如果你需要在Handler中访问外部activity的方法,可以在Handler中保持一个对Activity的WeakReference,这样就不会发生内存泄漏(上一篇文章有介绍)。
静态内部类和非静态内部类的区别很微小,那么如何选择?当内部类可以独立于Activity的生命周期而存在的时候,应该避免使用非静态的内部类,应该用静态内部类并且使用WeakReference保持对Activity的引用。
下一篇文章想给大家讲一下Android内存泄漏检测工具,还未研究,请期待吧。。。