提问者:小点点

我必须取消订阅已完成的可观察吗?


如果可观察对象完成,我是否仍然必须取消订阅/处置(在RxJava2中)可观察对象以删除观察者(防止内存泄漏),或者一旦发生on完成onError事件,这是否由RxJava内部处理?

其他类型怎么样,如可完成可流动等。


共2个答案

匿名用户

是的,你是正确的。

终止流后(已调用on完成/onError),订阅者会自动取消订阅。您应该能够在Subscription对象上使用isUn订阅()方法测试这些行为。

匿名用户

虽然您不需要手动取消订阅已终止的流,但如果不小心,您仍然可以使用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、BroadcastReccher或其生命周期由AndroidOS控制的任何类)。

Activity订阅了观察者,但随后在内存不足的情况下被AndroidOS销毁(您可以通过打开开发人员选项/不保留活动来模拟这种效果)。如果在Activity销毁时Schedulers.io()上的工作仍在运行,则仍将通过匿名内部类维护对Activity的引用。这意味着内存泄漏会阻止Activity被垃圾收集器最终确定。如果Activity有许多视图,或者说,一个位图对象,那么内存泄漏可能相当大。

这里有许多解决方案,但其中一个是维护一个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架构蓝图中有关如何在Android应用程序中使用RxJava的一个很好的示例。