@Tyhj
2019-05-19T07:15:51.000000Z
字数 4885
阅读 1350
Android
在执行网络请求的时候,网络不稳定或者超时的时候,获取数据时间比较长,用户可能已经退出这个界面了,这时候肯定会出现一些问题,首先因为Presenter还在请求数据,还持有Activity,就会导致内存泄漏
public NotPassPresenter(NotPassActivity activity) {mActivity = activity;mRepository = new ExpressRepository();}@Overridepublic void getNotPassRecord() {mRepository.getNotPassRecord(new IDataCallback<List<NotPassRecord>>() {@Overridepublic void success(List<NotPassRecord> notPassRecords) {getView().showNotPassRecord(notPassRecords);}@Overridepublic void fail(String msg) {getView().showMsg(msg);}});}@Overridepublic NotPassContract.View getView() {return mActivity;}
解决方案很简单,在Presenter中写一个destroy()方法,里面关闭资源,释放掉Activity
public void destory(){mActivity=null;}
然后重写Activity的onDestroy()方法,调用Presenter.destroy()方法
@Overrideprotected void onDestroy() {super.onDestroy();mNotPassPresenter.destory();}
这样Activity关闭的时候的确不会出现内存泄漏,但是获取到数据后getView()方法会返回为空造成内存泄漏,所以要判断不为空;但是说实话感觉太麻烦了,这些简单无脑的操作需要重复写无数遍,肯定不能接受的
Android Jetpack有一套可以解决的办法,使用LiveData和Lifecycles,但是我暂时感觉不是很适应,所以还是自己来实现一套。
首先Lifecycles的话感觉还是比较简单的,从Activity拿到Lifecycle,然后就可以使用它来监听生命周期变化,我们只需要在Presenter里面监听到Destroy的时候就释放掉资源;activity需要继承至FragmentActivity,AppCompatActivity也是一样的,它本身是继承至FragmentActivity的
public NotPassPresenter(NotPassActivity activity) {mActivity = activity;mRepository = new ExpressRepository();activity.getLifecycle().addObserver(new GenericLifecycleObserver() {@Overridepublic void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {if (event == Lifecycle.Event.ON_DESTROY) {mActivity = null;mRepository = null;}}});}
如果在每个Presenter的构造方法里面都写释放资源的代码也比较麻烦,可以写一个BasePresener来统一监听生命周期变化释放资源;而且通过反射其实可以释放里面的所有资源
package com.dhht.baselibrary.app;import android.arch.lifecycle.GenericLifecycleObserver;import android.arch.lifecycle.Lifecycle;import android.arch.lifecycle.LifecycleOwner;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentActivity;/*** @author HanPei* @date 2019/5/15 下午4:39*/public abstract class BasePresenter<T> {T mView;Lifecycle mLifecycle;protected BasePresenter(T view) {mView = view;FragmentActivity activity = null;if (mView instanceof FragmentActivity) {activity = (FragmentActivity) mView;} else if (mView instanceof Fragment) {activity = ((Fragment) mView).getActivity();}if (activity != null) {mLifecycle = activity.getLifecycle();mLifecycle.addObserver(new GenericLifecycleObserver() {@Overridepublic void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {if (event == Lifecycle.Event.ON_DESTROY) {release();}}});}}/*** 释放资源*/private void release() {mView = null;mLifecycle = null;/* Observable.just(0).observeOn(Schedulers.newThread()).subscribe(new Consumer<Integer>() {@Overridepublic void accept(Integer integer) throws Exception {//释放非静态变量Field[] fields = getClass().getDeclaredFields();for (Field field : fields) {try {field.setAccessible(true);//排除非静态变量和基本类型if (!field.getType().isPrimitive() && !Modifier.isStatic(field.getModifiers())) {field.set(this, null);}} catch (IllegalAccessException e) {e.printStackTrace();}}}});*/}/*** 获取View** @return*/protected T getView() {return mView;}protected Lifecycle getLifecycle() {return mLifecycle;}}
RxLifecycle 该项目是为了防止RxJava 中subscription导致内存泄漏而诞生的,核心思想是通过监听 Activity、Fragment 的生命周期,来自动断开 subscription 以防止内存泄漏。
基本用法如下:
myObservable.compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)).subscribe();
其实和上面的道理一样,当监听到Destroy的时候中断数据请求,那么IDataCallback就不会执行回调,自然不用去管getView()是否会为空;
方法其实还可以,只是我每次调用Model层的时候都需要把当前页面的lifecycle传进去,这个参数其实对于Model层来说是没有意义的,但是我的接口却必须加上这个参数,感觉还是有些不好;
IDataCallback执行回调,那应该可以从它入手
public interface IDataCallback<T> {/*** 获取数据成功** @param t*/void success(T t);/*** 获取数据失败** @param msg*/void fail(String msg);}
这是自己定义的返回数据的接口,很简单,每次获取到数据后调用回调方法
mRetrofitApi.getNotPassRecord().compose(Retrofite.applySchedulers()).subscribe(new BaseObserver<List<NotPassRecord>>() {@Overridepublic void sucess(List<NotPassRecord> notPassRecords) {callback.success(notPassRecords);}@Overridepublic void erro(String msg) {callback.fail(msg);}});
我们想在监听到页面关闭的时候不执行回调,就需要实现其中的方法,改动一下;
public abstract class BaseDataCallBack<T> implements IDataCallback<T> {/*** 是否中断回调*/private boolean breakOff;public BaseDataCallBack() {}public BaseDataCallBack(Lifecycle lifecycle) {lifecycle.addObserver(new GenericLifecycleObserver() {@Overridepublic void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {if (event.equals(Lifecycle.Event.ON_DESTROY)) {breakOff = true;}}});}@Overridepublic void success(T t) {if (!breakOff) {dataBack(t);}}@Overridepublic void fail(String msg) {if (!breakOff) {erroBack(msg);}}/*** 数据返回** @param t*/protected abstract void dataBack(T t);/*** 返回出错信息** @param msg*/protected abstract void erroBack(String msg);}
也非常简单,构造方法可以传入Lifecycle,监听到生命周期结束,那么不执行新的数据返回的回调方法,请求数据在设置监听的时候,重写这两个新的抽象方法就好了
public void getNotPassRecord() {mRepository.getNotPassRecord(new BaseDataCallBack<List<NotPassRecord>>() {@Overrideprotected void dataBack(List<NotPassRecord> notPassRecords) {getView().showNotPassRecord(notPassRecords);}@Overrideprotected void erroBack(String msg) {getView().showMsg(msg);}});}
感觉也还可以吧,没有依赖其他的框架,实现起来很简单,的确也解决了问题,用起来也方便;和RxLifecycle比起来的话,只是取消了回调,没取消数据请求,问题不大