web-dev-qa-db-ja.com

onNextおよびonCompleteの動作

値を出力する必要なしに何かを実行するObservableがあります。また、Observableで使用するオブジェクトのリストもあります。したがって、このリストのすべての要素について:doSomething()

Observable.from(uris)
        .flatMap(new Func1<Uri, Observable<Void>>() {
            @Override
            public Observable<Void> call(Uri uri) {
                return createDoSomethingObservable(uri);
            }
        })
        .observeOn(AndroidSchedulers.mainThread())
        .subscribeOn(Schedulers.io())
        .subscribe(new Observer<Void>() {
            @Override
            public void onCompleted() {
                Log.d(TAG, "completed");
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Void aVoid) {
                Log.d(TAG, "next");
            }
        });

そして、Observableを作成するメソッド:

Observable<Void> createDoSomethingObservable(final Uri uri) {
    return Observable.create(new Observable.OnSubscribe<Void>() {
        @Override
        public void call(Subscriber<? super Void> subscriber) {
            //doSomething
            subscriber.onNext(null);
            subscriber.onCompleted();
        }
    });
}

これを3つの要素を持つリストで実行すると、次のようになります。

next
next
next
completed

それは私が欲しかったものですが、それがなぜ機能しているのかわかりません。最初に、私はonCompleteを呼び出すようになりました。結局、オブザーバブルはその仕事をして完了します。しかしもちろん、サブスクライバーでonNextが呼び出されることはありません。同じことが逆の場合にも言えます。

だから私の質問は:

  1. OnCompleteが最後のリスト要素に対してのみ呼び出されるのはなぜですか?
  2. これを解決するより良い方法はありますか?
12
Kuno

最後の要素に対してonCompleteが呼び出されるのは、チェーン内の最も早いオブザーバブル(from(uris))が終了したためです。

flatMapから放出されたオブザーバブルはonCompleteを呼び出すことが期待されています。それが終わったら(そしてcallが戻ってきたら)、fromからの次の放出に取り組むことができます。 fromがオブザーバブルの出力を完了すると、onCompleteが呼び出され、チェーンが効果的に終了します。

7
Adam S

この小さなコードは、onNext( )onComplete()の動作を理解するのに役立つと思います。
あなたが_List<Uri>_を持っているとしましょう。 _Observable<Uri>_manuallyに変換しましょう。

_public static Observable<Uri> getUries(List<Uri> uriList){
    return Observable.create(new Observable.OnSubscribe<Uri>() {
        @Override
        public void call(Subscriber<? super Uri> subscriber) {
            for(Uri uri : uriList){
                subscriber.onNext(uri);
            }

            subscriber.onCompleted();
        }
    });
}
_

またはラムダ式を使用する:

_public static Observable<Uri> getUries(List<Uri> uriList){
    return Observable.create(subscriber -> {
        for(Uri uri : uriList){
            subscriber.onNext(uri);
        }

        subscriber.onCompleted();
    });
}
_

ご覧のとおり、入力リストを繰り返し、すべての要素に対してonNext( )を呼び出しています。ListObservableに変換し終えたら、onComplete()

PSこのコードは単なるデモンストレーションです。変換しないでくださいListからObservableへ。演算子Observable.from()を使用します。

[〜#〜]更新[〜#〜]

演算子from( )の実装:

_...
while (true) {
    if (o.isUnsubscribed()) {
        return;
    } else if (it.hasNext()) {
        o.onNext(it.next());
    } else if (!o.isUnsubscribed()) {
        o.onCompleted();
        return;
    } else {
        // is unsubscribed
        return;
    }
}
...
_

リンク: https://github.com/ReactiveX/RxJava/blob/1.x/src/main/Java/rx/internal/operators/OnSubscribeFromIterable.Java#L75-L87

5
Alexander

onCompleteonErrorと同じ)は、監視可能なチェーン中に一度だけ呼び出され、rxjavaが実装される方法です

あなたのアプローチは正しいと思うので、より良い方法は必要ありません。

2
pjanecze