Combinaison de Completables RxJava

1. Vue d'ensemble

Dans ce tutoriel, nous allons jouer avec le type Completable de RxJava , qui représente un résultat de calcul sans valeur réelle.

2. Dépendance RxJava

Incluons la dépendance RxJava 2 dans notre projet Maven:

 io.reactivex.rxjava2 rxjava 2.2.2 

Nous pouvons généralement trouver la dernière version sur Maven Central.

3. Type Completable

Completable est similaire à Observable à la seule exception que le premier émet des signaux d'achèvement ou d'erreur, mais aucun élément. Laclasse Completable contient plusieurs méthodes pratiques pour la créer ou l'obtenir à partir de différentes sources réactives.

Nous pouvons générer une instance qui se termine immédiatement en utilisant Completable.complete () .

Ensuite, nous pouvons observer son état en utilisant DisposableCompletableObserver :

Completable .complete() .subscribe(new DisposableCompletableObserver() { @Override public void onComplete() { System.out.println("Completed!"); } @Override public void onError(Throwable e) { e.printStackTrace(); } });

De plus, nous pouvons construire une instance Completable à partir de Callable, Action et Runnable :

Completable.fromRunnable(() -> {});

De plus, nous pouvons obtenir des instances Completable d'autres types en utilisant Completable.from () ou en appelant ignoreElement () sur les sources Maybe, Single, Flowable et Observable elles-mêmes:

Flowable flowable = Flowable .just("request received", "user logged in"); Completable flowableCompletable = Completable .fromPublisher(flowable); Completable singleCompletable = Single.just(1) .ignoreElement();

4. Chaînage Completables

Nous pouvons utiliser le chaînage de Completables dans de nombreux cas d'utilisation réels lorsque nous ne nous soucions que du succès de l'opération:

  • Actions tout ou rien comme faire une requête PUT pour mettre à jour un objet distant suivi d'une mise à jour de la base de données locale en cas de succès
  • Journalisation et journalisation post-factum
  • Orchestration de plusieurs actions, par exemple exécution d'un travail d'analyse après qu'une action d'ingestion est terminée

Nous garderons des exemples simples et indépendants des problèmes. Considérez que nous avons plusieurs instances Completable :

Completable first = Completable .fromSingle(Single.just(1)); Completable second = Completable .fromRunnable(() -> {}); Throwable throwable = new RuntimeException(); Completable error = Single.error(throwable) .ignoreElement();

Pour combiner deux Completables en une seule, nous pouvons utiliser l' opérateur andThen () :

first .andThen(second) .test() .assertComplete();

Nous pouvons enchaîner autant de Completables que nécessaire. En même temps, si au moins l' une des sources ne parvient pas à remplir, ce qui pouvant être complétée ne se déclenche pas onComplete () ainsi :

first .andThen(second) .andThen(error) .test() .assertError(throwable);

En outre, si l' une des sources est infinie ou ne pas atteindre onComplete pour une raison quelconque, le résultat pouvant être complétée ne sera jamais le feu onComplete () ni onError () aussi bien.

Une bonne chose que l'on puisse encore tester ce scénario:

... .andThen(Completable.never()) .test() .assertNotComplete();

5. Composer des séries de Completables

Imaginez que nous ayons un tas de Completables. En tant que cas d'utilisation pratique, supposons que nous ayons besoin d'enregistrer un utilisateur dans plusieurs sous-systèmes séparés.

Pour joindre tous les Completables en un seul, nous pouvons utiliser la famille de méthodes merge (). L' opérateur merge () permet de s'abonner à toutes les sources.

L'instance résultante se termine une fois que toutes les sources sont terminées . De plus, il se termine par onError lorsque l'une des sources émet une erreur:

Completable.mergeArray(first, second) .test() .assertComplete(); Completable.mergeArray(first, second, error) .test() .assertError(throwable);

Passons à un cas d'utilisation légèrement différent. Disons que nous devons exécuter une action pour chaque élément obtenu à partir d'un Flowable.

Ensuite, nous voulons un seul Completable à la fois pour l'achèvement de l'amont et pour toutes les actions au niveau de l'élément. L' opérateur flatMapCompletable () vient aider dans ce cas:

Completable allElementsCompletable = Flowable .just("request received", "user logged in") .flatMapCompletable(message -> Completable .fromRunnable(() -> System.out.println(message)) ); allElementsCompletable .test() .assertComplete();

De même, la méthode ci-dessus est disponible pour le reste des classes réactives de base comme Observable , Maybe ou Single.

As a practical context for flatMapCompletable(), we could think about decorating every item with some side effect. We can write a log entry per completed element or make a storage snapshot upon each successful action.

Finally, we may need to construct a Completable from a couple of other sources and get it terminated as soon as either of them completes. That's where amb operators can help.

The amb prefix is a short-hand for “ambiguous”, implying the uncertainty about which Completable exactly gets completed. For example, ambArray():

Completable.ambArray(first, Completable.never(), second) .test() .assertComplete();

Note, that the above Completable may also terminate with onError() instead of onComplete() depending on which source completable terminates first:

Completable.ambArray(error, first, second) .test() .assertError(throwable);

Also, once the first source terminates, the remaining sources are guaranteed to be disposed of.

That means all remaining running Completables are stopped via Disposable.dispose() and corresponding CompletableObservers will be unsubscribed.

Concerning a practical example, we can use amb() when we stream a backup file to a several equivalents remote storages. And we complete the process once the first-best backup finishes or repeat the process upon error.

6. Conclusion

In this article, we briefly reviewed the Completable type of RxJava.

Nous avons commencé avec différentes options pour obtenir des instances Completable , puis avons chaîné et composé des Completables en utilisant les opérateurs andThen (), merge (), flatMapCompletable () et amb… () .

Nous pouvons trouver la source de tous les exemples de code sur GitHub.