最近的一个项目,是采用由RxJava、LiveData提供支持的响应式架构。尽管这些库功能强大,内存泄漏的情况;
什么是内存泄漏
内存中不再使用的对象,被另一个正在使用的对象引用,导致 GC 无法清除它并释放内存
如果我们有两个相互持有强引用的对象,即使没有任何外部引用,也会发生内存泄漏。这就是所谓的保留周期。这在 Android 上通常不是问题,因为 Java GC 使用的是标记和清除算法。
一,rxjava的内存泄漏
(1)存在内存泄漏问题
在使用rxjava的时候,如果没有及时解除订阅,在退出activity的时候,异步线程还在执行。对activity还存在引用,此时就会产生内存泄漏。
(2)常规手动取消订阅(不推荐)
为了防止内存泄漏的出现,我们需要在onDestroy取消订阅
Observable.interval(1000, TimeUnit.MILLISECONDS) .subscribe(new Observer<Long>() { @Override public void onSubscribe(Disposable d) { disposable = d; } @Override public void onNext(Long aLong) { } @Override public void onError(Throwable e) { } @Override public void onComplete() { } });
@Override protected void onDestroy() { if(disposable != null && !disposable.isDisposed()){ //取消订阅 disposable.dispose(); } super.onDestroy(); }
以上代码的缺点很明显:
必须在onSubscribe中保存Disposable对象,然后在onDestroy方法里面取消订阅,如果有多个Observable时,很明显Disposable也会有多个,这样代码看起来紊乱,逻辑复杂,可读性差。
那么有没有什么办法对Disposable统一管理呢?
3)使用CompositeDisposable来管理Disposable
CompositeDisposable是一个存放Disposable的集合,它是一个容器,可以在BaseActivity里new一个CompositeDisposable对象,在BaseActivity的子类中可以使用该对象对Disposable统一管理。
CompositeDisposable也属于手动取消订阅,但显然比单独管理Disposable的方法强多了。
(4)RxLifecycle(自动取消订阅)(推荐)
Observable .interval(1000, TimeUnit.MILLISECONDS) .compose(this.<Long>bindUntilEvent(ActivityEvent.DESTROY)) .subscribe(new Consumer<Long>() { @Override public void accept(Long aLong) throws Exception { Log.d("aaa", String.valueOf(aLong)); } });
RxLifecycle将Observable和Activity(Fragment)的生命周期绑定在一起,使用compose关键字来确定Observable将要在哪个生命周期执行时自动取消订阅
(5)AutoDispose(自动取消订阅)(推荐)
Observable .interval(1000, TimeUnit.MILLISECONDS) //AutoDispose的关键语句 .as(AutoDispose.<Long>autoDisposable(AndroidLifecycleScopeProvider.from(this))) .subscribe(new Consumer<Long>() { @Override public void accept(Long aLong) throws Exception { Log.d("aaa", String.valueOf(aLong)); } });
AutoDispose要比RxLifecycle更加简单,有人说使用AutoDispose取代RxLifecycle也是有一定道理的,毕竟RxLifecycle需要继承对应的RxActivity、RxFragment,而AutoDispose却不用
二,LiveData可能产生的泄漏分析
订阅LiveData错误使用context
有一个RecyclerView通过. 渲染 a 的片段Adapter。您将如何观察项目列表并更新Adapter? 通常你会在你的订阅中拥有一个LiveData项目,然后使用.ViewModelDiffUtil
但是您会在哪里定义该订阅?有两种可能的选择:您可以在片段中创建订阅,然后将更新的项目列表发送到Adapter,或者您可以将您的传递ViewModel给Adapter并Adapter直接观察更改.
最后,LiveData 与 RxJava
虽然 LiveData 和 RxJava 都属于观察者模式的实现,但是他们的本质是完全不同的。
LiveData 只是数据的储存类,本身不支持复杂的线程操作和事件序列,也没有异常处理。与 RxJava 相比,具有体积小,学习成本低等优点。
RxJava 是一个完整的基于事件的观察序列,用来处理异步操作的框架。使用 RxJava 可以方便的切换线程,同时 RxJava 拥有的众多操作符也可以让逻辑变的清晰可循。配合 Retrofit 大大地简化了网络操作。但是学习曲线较陡,大部分人只会一些简单的操作。