web-dev-qa-db-fra.com

Comportement de onNext et onComplete

J'ai un observable qui fait quelque chose sans avoir besoin d'émettre une valeur. J'ai aussi une liste d'objets avec lesquels je souhaite que l'Observable fonctionne. Donc, pour tous les éléments de cette liste: doQuelque chose ()

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");
            }
        });

Et la méthode qui crée l'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();
        }
    });
}

Maintenant, quand je lance ceci avec une liste avec 3 éléments, je reçois:

next
next
next
completed

ce qui est bien, car c'est ce que je voulais, mais je ne sais pas pourquoi ça marche. J'ai d'abord commencé à appeler onComplete, parce qu'en fin de compte l'observable fait son travail et se termine. Mais bien entendu, onNext n'est jamais appelé sur l'abonné. Il en va de même pour l'inverse.

Donc mes questions sont:

  1. Pourquoi onComplete n'est appelé que pour le dernier élément de la liste?
  2. Y a-t-il une meilleure façon de résoudre ce problème?
12
Kuno

onComplete est appelé pour le dernier élément parce que c'est à la fin de la première observation observable dans la chaîne (from(uris)).

Il est prévu que vos variables observables émises par flatMap appelleront onComplete. Une fois que cela est fait (et que call est revenu), la prochaine émission de from peut alors être traitée. Une fois que from a fini d'émettre des éléments observables, il appelle onComplete et la chaîne est terminée, de manière efficace.

6
Adam S

Je pense que ce petit code vous aide à comprendre le comportement de onNext( ) et onComplete().
Supposons que vous ayez un List<Uri>. Transformons-le en Observable<Uri>manuellement.

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();
        }
    });
}

Ou en utilisant des expressions Lambda:

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

        subscriber.onCompleted();
    });
}

Comme vous pouvez le constater, nous itérons une liste d’entrées et appelons onNext( ) pour chaque élément. Lorsque nous avons fini de transformer notre List en Observable, nous avons appelé onComplete().

P.S. Ce code est juste une démonstration, s'il vous plaît, ne l'utilisez jamais pour transformer List en Observable. Utilisez l'opérateur Observable.from() pour cela.

METTRE &AGRAVE; JOUR:

Implémentation de l'opérateur 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;
    }
}
...

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

5
Alexander

onComplete (identique à onError) n'est appelée qu'une fois pendant la chaîne observable, c'est la manière dont rxjava est implémenté

Je pense que votre approche est correcte, alors un meilleur moyen n'est pas nécessaire.

0
pjanecze