[关闭]
@Tyhj 2019-05-19T15:15:51.000000Z 字数 4885 阅读 1145

Android界面关闭数据请求未结束

Android


网络请求导致内存泄漏

在执行网络请求的时候,网络不稳定或者超时的时候,获取数据时间比较长,用户可能已经退出这个界面了,这时候肯定会出现一些问题,首先因为Presenter还在请求数据,还持有Activity,就会导致内存泄漏

  1. public NotPassPresenter(NotPassActivity activity) {
  2. mActivity = activity;
  3. mRepository = new ExpressRepository();
  4. }
  5. @Override
  6. public void getNotPassRecord() {
  7. mRepository.getNotPassRecord(new IDataCallback<List<NotPassRecord>>() {
  8. @Override
  9. public void success(List<NotPassRecord> notPassRecords) {
  10. getView().showNotPassRecord(notPassRecords);
  11. }
  12. @Override
  13. public void fail(String msg) {
  14. getView().showMsg(msg);
  15. }
  16. });
  17. }
  18. @Override
  19. public NotPassContract.View getView() {
  20. return mActivity;
  21. }

简单的解决方案

解决方案很简单,在Presenter中写一个destroy()方法,里面关闭资源,释放掉Activity

  1. public void destory(){
  2. mActivity=null;
  3. }

然后重写ActivityonDestroy()方法,调用Presenter.destroy()方法

  1. @Override
  2. protected void onDestroy() {
  3. super.onDestroy();
  4. mNotPassPresenter.destory();
  5. }

这样Activity关闭的时候的确不会出现内存泄漏,但是获取到数据后getView()方法会返回为空造成内存泄漏,所以要判断不为空;但是说实话感觉太麻烦了,这些简单无脑的操作需要重复写无数遍,肯定不能接受的

引入Lifecycles

Android Jetpack有一套可以解决的办法,使用LiveDataLifecycles,但是我暂时感觉不是很适应,所以还是自己来实现一套。

首先Lifecycles的话感觉还是比较简单的,从Activity拿到Lifecycle,然后就可以使用它来监听生命周期变化,我们只需要在Presenter里面监听到Destroy的时候就释放掉资源;activity需要继承至FragmentActivityAppCompatActivity也是一样的,它本身是继承至FragmentActivity

  1. public NotPassPresenter(NotPassActivity activity) {
  2. mActivity = activity;
  3. mRepository = new ExpressRepository();
  4. activity.getLifecycle().addObserver(new GenericLifecycleObserver() {
  5. @Override
  6. public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
  7. if (event == Lifecycle.Event.ON_DESTROY) {
  8. mActivity = null;
  9. mRepository = null;
  10. }
  11. }
  12. });
  13. }

如果在每个Presenter的构造方法里面都写释放资源的代码也比较麻烦,可以写一个BasePresener来统一监听生命周期变化释放资源;而且通过反射其实可以释放里面的所有资源

  1. package com.dhht.baselibrary.app;
  2. import android.arch.lifecycle.GenericLifecycleObserver;
  3. import android.arch.lifecycle.Lifecycle;
  4. import android.arch.lifecycle.LifecycleOwner;
  5. import android.support.v4.app.Fragment;
  6. import android.support.v4.app.FragmentActivity;
  7. /**
  8. * @author HanPei
  9. * @date 2019/5/15 下午4:39
  10. */
  11. public abstract class BasePresenter<T> {
  12. T mView;
  13. Lifecycle mLifecycle;
  14. protected BasePresenter(T view) {
  15. mView = view;
  16. FragmentActivity activity = null;
  17. if (mView instanceof FragmentActivity) {
  18. activity = (FragmentActivity) mView;
  19. } else if (mView instanceof Fragment) {
  20. activity = ((Fragment) mView).getActivity();
  21. }
  22. if (activity != null) {
  23. mLifecycle = activity.getLifecycle();
  24. mLifecycle.addObserver(new GenericLifecycleObserver() {
  25. @Override
  26. public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
  27. if (event == Lifecycle.Event.ON_DESTROY) {
  28. release();
  29. }
  30. }
  31. });
  32. }
  33. }
  34. /**
  35. * 释放资源
  36. */
  37. private void release() {
  38. mView = null;
  39. mLifecycle = null;
  40. /* Observable.just(0)
  41. .observeOn(Schedulers.newThread())
  42. .subscribe(new Consumer<Integer>() {
  43. @Override
  44. public void accept(Integer integer) throws Exception {
  45. //释放非静态变量
  46. Field[] fields = getClass().getDeclaredFields();
  47. for (Field field : fields) {
  48. try {
  49. field.setAccessible(true);
  50. //排除非静态变量和基本类型
  51. if (!field.getType().isPrimitive() && !Modifier.isStatic(field.getModifiers())) {
  52. field.set(this, null);
  53. }
  54. } catch (IllegalAccessException e) {
  55. e.printStackTrace();
  56. }
  57. }
  58. }
  59. });*/
  60. }
  61. /**
  62. * 获取View
  63. *
  64. * @return
  65. */
  66. protected T getView() {
  67. return mView;
  68. }
  69. protected Lifecycle getLifecycle() {
  70. return mLifecycle;
  71. }
  72. }

取消数据请求

RxLifecycle 该项目是为了防止RxJava 中subscription导致内存泄漏而诞生的,核心思想是通过监听 Activity、Fragment 的生命周期,来自动断开 subscription 以防止内存泄漏。

基本用法如下:

  1. myObservable
  2. .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY))
  3. .subscribe();

其实和上面的道理一样,当监听到Destroy的时候中断数据请求,那么IDataCallback就不会执行回调,自然不用去管getView()是否会为空;

方法其实还可以,只是我每次调用Model层的时候都需要把当前页面的lifecycle传进去,这个参数其实对于Model层来说是没有意义的,但是我的接口却必须加上这个参数,感觉还是有些不好;

IDataCallback执行回调,那应该可以从它入手

  1. public interface IDataCallback<T> {
  2. /**
  3. * 获取数据成功
  4. *
  5. * @param t
  6. */
  7. void success(T t);
  8. /**
  9. * 获取数据失败
  10. *
  11. * @param msg
  12. */
  13. void fail(String msg);
  14. }

这是自己定义的返回数据的接口,很简单,每次获取到数据后调用回调方法

  1. mRetrofitApi.getNotPassRecord()
  2. .compose(Retrofite.applySchedulers())
  3. .subscribe(new BaseObserver<List<NotPassRecord>>() {
  4. @Override
  5. public void sucess(List<NotPassRecord> notPassRecords) {
  6. callback.success(notPassRecords);
  7. }
  8. @Override
  9. public void erro(String msg) {
  10. callback.fail(msg);
  11. }
  12. });

我们想在监听到页面关闭的时候不执行回调,就需要实现其中的方法,改动一下;

  1. public abstract class BaseDataCallBack<T> implements IDataCallback<T> {
  2. /**
  3. * 是否中断回调
  4. */
  5. private boolean breakOff;
  6. public BaseDataCallBack() {
  7. }
  8. public BaseDataCallBack(Lifecycle lifecycle) {
  9. lifecycle.addObserver(new GenericLifecycleObserver() {
  10. @Override
  11. public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
  12. if (event.equals(Lifecycle.Event.ON_DESTROY)) {
  13. breakOff = true;
  14. }
  15. }
  16. });
  17. }
  18. @Override
  19. public void success(T t) {
  20. if (!breakOff) {
  21. dataBack(t);
  22. }
  23. }
  24. @Override
  25. public void fail(String msg) {
  26. if (!breakOff) {
  27. erroBack(msg);
  28. }
  29. }
  30. /**
  31. * 数据返回
  32. *
  33. * @param t
  34. */
  35. protected abstract void dataBack(T t);
  36. /**
  37. * 返回出错信息
  38. *
  39. * @param msg
  40. */
  41. protected abstract void erroBack(String msg);
  42. }

也非常简单,构造方法可以传入Lifecycle,监听到生命周期结束,那么不执行新的数据返回的回调方法,请求数据在设置监听的时候,重写这两个新的抽象方法就好了

  1. public void getNotPassRecord() {
  2. mRepository.getNotPassRecord(new BaseDataCallBack<List<NotPassRecord>>() {
  3. @Override
  4. protected void dataBack(List<NotPassRecord> notPassRecords) {
  5. getView().showNotPassRecord(notPassRecords);
  6. }
  7. @Override
  8. protected void erroBack(String msg) {
  9. getView().showMsg(msg);
  10. }
  11. });
  12. }

感觉也还可以吧,没有依赖其他的框架,实现起来很简单,的确也解决了问题,用起来也方便;和RxLifecycle比起来的话,只是取消了回调,没取消数据请求,问题不大

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注