发生内存泄露的场景:
场景1:静态变量引用Activity对象
场景2:静态View
场景3:内部类和匿名类
场景4:Handler
场景5:Threads和TimerTask
场景6:监听器
场景7:静态集合对象引起的泄漏
场景8:资源对象未关闭
场景9:使用对象池避免频繁创建对象
场景10:Back键退出引起的泄漏
现在有这么一个场景(场景3|场景6):在Activity里定义了一个Listener,这个Listener的实例需要以参数的形式传递到SDK里,SDK执行完耗时的操作(比如扫描蓝牙),然后执行该Listener的回调方法。这样一来,在扫描的过程中,如果我们按了返回键,Activity并不能正常销毁,因为SDK拥有Listener的强引用,这样就发生了内存泄露。
解决方法:
1. SDK提供了停止耗时操作的接口,那么在销毁Actiivity的时候调用该接口停止耗时操作即可。
2. 假设没有提供相关接口,可使用观察者模式解决:
①编写一个被观察者接口:
/**
* Created by zhanzc on 2017/7/18.
* 被观察者
*/
public interface IObservable {
void update();
}
②编写一个观察者:
/**
* Created by zhanzc on 2017/7/18.
* 观察者类
*/
public class DataWatcher {
private static DataWatcher dataWatcher;
private DataWatcher(){}
public static DataWatcher getInstance() {
if (dataWatcher == null) {
initWatcher();
}
return dataWatcher;
}
private static synchronized void initWatcher() {
if (dataWatcher == null) {
dataWatcher = new DataWatcher();
}
}
// 一般来说,这应该是一个集合,但我这里只监听可能发生内存泄露的Activity,所以只用了一个observable
private IObservable observable;
/**
* 添加被观察者
* @param observable
*/
public void register(IObservable observable) {
this.observable = observable;
}
/**
* 解除监听
*/
public void unregister(IObservable ob) {
this.observable = null;
}
/**
* 通知被观察者更新数据
*/
public void notifyObservable() {
if (this.observable != null) {
this.observable.update();
}
}
}
③Activity实现接口成为被观察者,实现相关方法:
@Override
public void update() {
// 更新UI
}
④onCreate()方法执行
// 观察者观察被观察者
DataWatcher.getInstance().register(this);
⑤Linstener的class定义为static
⑥Listener的回调里调用:
// 通知被观察者更新数据
DataWatcher.getInstance().notifyObservable();
⑦onDestroy()执行:
// 解除观察
DataWatcher.getInstance().unregister(this);
如果你的项目引入了EventBus或RxJava等有订阅/被订阅关系的框架,也可以直接使用,操作都一样。