web-dev-qa-db-ja.com

サブスクリプションを解除するタイミング

オブザーバブルの購読を解除する方法について質問があります。私は2つのコードを持っていますが、どちらが良いかについては本当にわかりません。

例1->ストリームが終了したら、サブスクライバーをサブスクライブ解除します。

Subscriber<String> subscriber = new Subscriber<String>() {
        @Override
        public void onCompleted() {
            progressdialog.dissmiss();
            unsubscribe();
        }

        @Override
        public void onError(Throwable e) {
            progressdialog.dissmiss();
        }

        @Override
        public void onNext(String s) {
            // do something with data
        }
    }

例2->アクティビティが破棄されたらサブスクリプションのサブスクリプションを解除します。

private void test(){
    Subscriber<String> subscriber = new Subscriber<String>() {
        @Override
        public void onCompleted() {
            progressdialog.dissmiss();
        }

        @Override
        public void onError(Throwable e) {
            progressdialog.dissmiss();
        }

        @Override
        public void onNext(String s) {
            // do something with data
        }
    };

    subscription = BackendRequest.login(loginRequest)
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(subscriber);

    compositeSubscription.add(subscription);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    this.subscription.unsubscribe();
}

私のオブザーバブルは1回しか放出されず、アクティビティはObservableからの呼び出しを待つべきではないことに言及する必要があります。

どっちがいいですか?

前もって感謝します

29
MarcForn

2つのオプションから、2番目のオプションの方が優れています。

最初の例では、onComplete()メソッドのunsubscribingは不要です。サブスクリプションのonComplete()に到達した場合、サブスクリプションのサブスクリプションを解除する責任はもうありません。

2番目の例は正しい例です。 CompositeSubscriptionの背後にある考え方は、複数のSubscriptionsを追加して、一度に(unsubscribe)をクリーンアップできるということです。言い換えれば、これにより、購読を解除する必要があるSubscriptionsのリストを保持する必要がなくなります。

CompositeSubscriptionを使用するトリッキーな部分は、一度unsubscribe itすると、[〜#〜] not [〜#〜]再度使用します。理由の詳細については、 compositeSubscription.add() メソッドのドキュメントを確認できます。つまり、追加しようとしているサブスクリプションのサブスクリプションを直接解除します。これは意図的な決定でした(詳細については、こちらをご覧ください [〜#〜] here [〜#〜] )。

あなたの例に戻って、アクティビティのunsubscribe()onDestroy()を呼び出すことは問題なく、メモリリークからあなたを救います。あなたのコメントに関して、test()メソッドを複数回呼び出すと問題が発生する-あなたの問題はどこか別の場所にあると思います。あなたのユースケースはそれを複数回呼び出すことを許可すべきではないかもしれません、おそらく新しく受け取ったデータを使用する前に古いデータをクリーンアップする必要があるかもしれません。おそらくあなたが直面しているどんな種類の問題を詳細に説明したなら、私たちはもっと役立つでしょう。ただし、CompositeSubscriptionに関する限り-あなたはそれを使用し、正しくサブスクライブを解除しています!

28
Vesko

onCompletedでサブスクライブを解除する必要はありません。 観察可能な契約 を見てください

ObservableがそのオブザーバーにOnErrorまたはOnComplete通知を発行すると、サブスクリプションが終了します。オブザーバーは、この方法でObservableによって終了されたサブスクリプションを終了するために、サブスクライブ解除通知を発行する必要はありません。

一方、メモリリークを防ぐためには、onDestroyでサブスクライブを解除する必要があります。

28
MyDogTom

それはあなたのニーズ次第だと思います。アクティビティが他の呼び出しを待機しない場合、onCompleted()内でサブスクライブを解除できると思います。

私は常にonDestroy()で退会します

@Override
protected void onDestroy() {
    super.onDestroy();

    if (subscription != null) {
        subscription.unsubscribe();
    }
}

編集: http://reactivex.io/RxJava/javadoc/rx/subscriptions/CompositeSubscription.html をご覧ください

private CompositeSubscription mCompositeSubscription = new CompositeSubscription();

private void doSomething() {
    mCompositeSubscription.add(
        AndroidObservable.bindActivity(this, Observable.just("Hello, World!"))
       .subscribe(s -> System.out.println(s)));
}

@Override
protected void onDestroy() {
    super.onDestroy();
    mCompositeSubscription.unsubscribe();
}
5