自定义接口回调操作不当容易导致内存泄漏
- 列表第一项面试中,经常被问到MVP是否会导致内存泄漏,相信很多人都说会导致,但是如何解决,大部分人都是回答说,使用lifecycle,让第三方来托管泄漏问题,但是真正使用中,如果没有理解泄漏的原理还是不够的。
- 撇开MVP来说,我们日常也经常喜欢使用自定义的interface来操作一系列的接口回调,这样可以一定程度上降低我们的耦合,但是不管是使用MVP或者自定义interface都是会由于在子线程操作耗时动作导致泄漏。举个栗子吧
public interface LoginInterface{
void onLoginSuccess();
void onLoginFailed();
}
如上的使用,是我们日常开发最常见的使用方式了。我们猜想下,如果我们使用了网络请求,这个操作还没有执行完毕的时候,回调里面的匿名内部类已经隐式的持有了外部类的引用,这就导致了内存无法被回收,为什么无法被回收呢?可以参考下JVM垃圾回收机制里面的标记回收法,这里不做详细记录。来看看有可能导致泄漏的伪代码吧。
LoginInterface loginInterface = new LoginInterface ();
public void login(User user){
RetrofitClient.getInstance().login(user).subscriber(
new Consumer(<BaseResponse> response){
loginInterface.onLoginSuccess();
},new Consumer(<Exception> ex){
loginInterface.onLoginFailed();
}
}
通过以上伪代码,我们可以看到,登录是个耗时操作,这个时候,如果是弱网络情况下,我们强制退出当前页面,那么onLoginSuccess 和 onLoginFailed 由于会持有Activity的外部类引用,导致JVM无法回收,造成了内存泄漏。所以,需要这么解决
protected Reference<LoginInterface > weakLoginInterface;
//View接口类型弱引用
public void login(User user,LoginInterface loginInterface){
weakLoginInterface= new Reference<LoginInterface >(loginInterface);
RetrofitClient.getInstance().login(user).subscriber(
new Consumer(<BaseResponse> response){
if(weakLoginInterface.get()==null)return;
weakLoginInterface.get().onLoginSuccess();
},new Consumer(<Exception> ex){
if(weakLoginInterface.get()==null)return;
weakLoginInterface.get().onLoginFailed();
}
}
添加弱引用,来避免当Activity被销毁的时候,内存无法回收的情况,弱引用为啥可以解决,这里不做解释,仅给出方案。在Activity OnDestory的时候,调用
public void detachView() {//解除关联
if (weakLoginInterface!= null) {
weakLoginInterface.clear();
weakLoginInterface= null;
}
}
以上方案也适用于MVP的常规内存泄漏解决方案,接收的
protected Reference<T> weakInterface;使用泛型来接受,定义在BasePresenter,在Activity的OnDestory方法调用P层内部方法detachView(),解除关联,并把P置null(如果有需要)
网友评论