原 Android 使用RxLifecycle解决RxJava内存泄漏

匿名 (未验证) 提交于 2019-12-02 21:53:52



RxLifecycle GitHub地址

RxJava GitHub地址

1.为什么会发生内存泄漏


写段代码测试一下,定义一个Activity,布局中显示一张图片,这样可以直观的看到此Activity的内存占用情况,然后在Activity中发布一个订阅后,关闭Activity,订阅逻辑如下:

// 每隔1s执行一次事件 Observable.interval(1, TimeUnit.SECONDS)         .subscribeOn(Schedulers.io())         .observeOn(AndroidSchedulers.mainThread())         .subscribe(new Observer<Long>() {             @Override             public void onSubscribe(@NonNull Disposable d) {              }              @Override             public void onNext(@NonNull Long aLong) {                 Log.i("接收数据", String.valueOf(aLong));             }              @Override             public void onError(@NonNull Throwable e) {              }              @Override             public void onComplete() {              }         });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

看下打开Activity之前的内存占用情况:

打开Activity之后的内存占用情况:

-

关闭Activity,手动执行GC(点击小车图标),发现内存占用并没有减少:

导出hprof文件进行分析(点击小车图标右边的图标),发现已经发生了内存泄漏:

那么除了在onDestory方法中手动取消订阅之外,还有什么方法可以避免上述的泄漏问题呢,这时RxLifecycle就派上用场了。

2.RxLifecycle是什么

看下官方的介绍:

This library allows one to automatically complete sequences based on a second lifecycle stream.

This capability is useful in Android, where incomplete subscriptions can cause memory leaks.

大概意思就是:可以通过绑定生命周期的方式,来解决内存泄漏的问题。

3.实践

看下使用RxLifecycle需要依赖的库:

// RxLifecycle基础库 compile 'com.trello.rxlifecycle2:rxlifecycle:2.1.0'  // Android使用的库,里面使用了Android的生命周期方法 // 内部引用了基础库,如果使用此库则无需再引用基础库 compile 'com.trello.rxlifecycle2:rxlifecycle-android:2.1.0'  // Android组件库,里面定义了例如RxAppCompatActivity、RxFragment之类的Android组件 // 内部引用了基础库和Android库,如果使用此库则无需再重复引用 compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'  // Android使用的库,继承NaviActivity使用 compile 'com.trello.rxlifecycle2:rxlifecycle-navi:2.1.0'  // Android使用的库,继承LifecycleActivity使用 // 需要引入Google的仓库支持,用法和rxlifecycle-navi类似 compile 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.1.0'  // Google的仓库支持 allprojects {     repositories {         jcenter()         maven { url 'https://dl.google.com/dl/android/maven2/' }     } }  // 支持Kotlin语法的RxLifecycle基础库 compile 'com.trello.rxlifecycle2:rxlifecycle-kotlin:2.1.0'  // 支持Kotlin语法的Android库 compile 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle-kotlin:2.1.0'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

本文需要依赖其中两个库:

// 依赖以下两个库,会自动引用基础库与Android库 compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0' compile 'com.trello.rxlifecycle2:rxlifecycle-navi:2.1.0'
  • 1
  • 2
  • 3

rxlifecycle-components

public class RxLifecycleComponentsActivity extends RxAppCompatActivity {      @Override     protected void onCreate(@Nullable Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_rxlifecycle_components);     }      @Override     protected void onStart() {         super.onStart();         Observable.interval(1, TimeUnit.SECONDS)                 .subscribeOn(Schedulers.io())                 .observeOn(AndroidSchedulers.mainThread())                 .compose(this.<Long>bindToLifecycle())                 .subscribe();     } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

使用compose(this.bindToLifecycle())方法绑定Activity的生命周期,在onStart方法中绑定,在onStop方法被调用后就会解除绑定,以此类推。

有一种特殊情况,如果在onPause/onStop方法中绑定,那么就会在它的下一个生命周期方法(onStop/onDestory)被调用后解除绑定。


除了使用bindToLifecycle的方式之外,还可以指定取消订阅的时机:

public class RxLifecycleComponentsActivity extends RxAppCompatActivity {      @Override     protected void onCreate(@Nullable Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_rxlifecycle_components);         ButterKnife.bind(this);          initData();     }      private void initData() {         Observable.interval(1, TimeUnit.SECONDS)                 .subscribeOn(Schedulers.io())                 .observeOn(AndroidSchedulers.mainThread())                 .compose(this.<Long>bindUntilEvent(ActivityEvent.DESTROY))                 .subscribe();     } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19


注意compose方法需要在subscribeOn方法之后使用,因为在测试的过程中发现,将compose方法放在subscribeOn方法之前,如果在被观察者中执行了阻塞方法,比如Thread.sleep(),取消订阅后该阻塞方法不会被中断。

Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {             @Override             public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {                 try {                     Thread.sleep(60 * 1000);                 } catch (InterruptedException ex) {                     ex.printStackTrace();                 }             }         });         observable                 .subscribeOn(Schedulers.io())                 .observeOn(AndroidSchedulers.mainThread())                 .compose(this.<String>bindUntilEvent(ActivityEvent.DESTROY))                 .subscribe();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

rxlifecycle-navi

public class RxLifecycleNaviActivity extends NaviActivity {      private final LifecycleProvider<ActivityEvent> provider             = NaviLifecycle.createActivityLifecycleProvider(this);      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_rxlifecycle_navi);         ButterKnife.bind(this);          initData();     }      private void initData() {         Observable.interval(1, TimeUnit.SECONDS)                 .subscribeOn(Schedulers.io())                 .observeOn(AndroidSchedulers.mainThread())                 .compose(provider.<Long>bindUntilEvent(ActivityEvent.DESTROY))                 .subscribe(new Observer<Long>() {                     @Override                     public void onSubscribe(@NonNull Disposable d) {                      }                      @Override                     public void onNext(@NonNull Long aLong) {                         Log.i("接收数据", String.valueOf(aLong));                     }                      @Override                     public void onError(@NonNull Throwable e) {                      }                      @Override                     public void onComplete() {                      }                 });     }      @Override     protected void onStart() {         super.onStart();         Observable.interval(1, TimeUnit.SECONDS)                 .subscribeOn(Schedulers.io())                 .observeOn(AndroidSchedulers.mainThread())                 .compose(provider.<Long>bindToLifecycle())                 .subscribe(new Observer<Long>() {                     @Override                     public void onSubscribe(@NonNull Disposable d) {                      }                      @Override                     public void onNext(@NonNull Long aLong) {                         Log.i("接收数据", String.valueOf(aLong));                     }                      @Override                     public void onError(@NonNull Throwable e) {                      }                      @Override                     public void onComplete() {                      }                 });     } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

继承了NaviActivity,通过NaviLifecycle.createActivityLifecycleProvider(this)方法获取LifecycleProvider对象,有了LifecycleProvider对象之后就可以调用bindToLifecycle或者bindUntilEvent方法了。

如果你使用的是MVP结构,这个LifecycleProvider对象可以直接传给Presenter层使用。

继承RxAppCompatActivity为什么就能直接用this的方式调用bindToLifecycle或bindUntilEvent方法呢?看下源码,原来RxAppCompatActivity实现了LifecycleProvider接口。

public abstract class RxAppCompatActivity extends AppCompatActivity implements LifecycleProvider<ActivityEvent> { }
  • 1
  • 2

4.写在最后

源码已托管到GitHub上,欢迎Fork,觉得还不错就Start一下吧!

GitHub传送门

欢迎同学们吐槽评论,如果你觉得本篇博客对你有用,那么就留个言或者顶一下吧(^-^)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!