我是否必须取消订阅已完成的观察?

时间:2017-01-24 11:00:59

标签: java rx-java rx-java2

如果一个observable完成了,我是否仍然需要取消订阅/处置(在RxJava2中)observable以删除Observer(防止内存泄漏)或者这是由RxJava在onComplete或{{1}后内部处理的事件发生了吗?

其他类型如onErrorSingleCompletable等等。

2 个答案:

答案 0 :(得分:18)

是的,你是对的。

终止流后(已调用onComplete / onError),订阅者自动取消订阅。您应该能够使用订阅对象上的isUnsubscribed()方法测试这些行为。

答案 1 :(得分:5)

虽然您不需要手动取消订阅已终止的流,但如果您不小心,仍可以使用RxJava2创建内存泄漏。

请考虑以下代码:

repository.getData()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(data -> myTextView.setText(data.toString()));

订阅中的lambda参数是"合成糖"在一个匿名的内部阶级:

subscribe(new Consumer<Data>() {
    @Override
    public void accept(final Data data) {
        myTextView.setText(data.toString());
    }
});

在JVM上,匿名内部类维护对外部类的引用。

假设对于上面的天真代码,外部类是一个Activity(这也适用于Fragment,Service,BroadcastReceiver或其生命周期由Android OS控制的任何类)。

活动订阅观察者但是在内存不足的情况下被Android操作系统销毁(你可以通过打开开发者选项/不要保持活动来模仿这种效果)。如果在销毁活动时Schedulers.io()上的工作仍在运行,则仍将通过匿名内部类向活动维护引用。这意味着内存泄漏会阻止垃圾收集器完成活动。如果Activity有多个Views或比如Bitmap对象,那么内存泄漏可能非常大。

这里有很多解决方案,但其中一个是维护一个CompositeDisposable对象,并在Android Activity的onDestroy()生命周期方法中清除它:

public class MyActivity extends Activity {

   DataRepository dataRepository;
   CompositeDisposable disposables;

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       disposables = new CompositeDisposable();
   }

   public void onButtonClick(View v) {
       repository.getData()             
          .subscribeOn(Schedulers.io())
          .observeOn(AndroidSchedulers.mainThread())
          .doOnSubscribe(disposable -> disposables.add(disposable))
          .subscribe(data -> myTextView.setText(data.toString()));
   }

   @Override
   public void onDestroy() {
       disposables.clear();
       super.onDestroy();
   }
}

您可以参考官方Google Android Architecture Blueprints中Android应用中如何使用RxJava的一个很好的示例。