Conversion d’API synchrones et asynchrones en observables à l’aide de RxJava2

Conversion d'API synchrones et asynchrones en observables à l'aide de RxJava2

1. Vue d'ensemble

Dans ce tutoriel, nous allons apprendre les opérateurshow to transform traditional synchronous and asynchronous APIs into Observables using RxJava2.

Nous allons créer quelques fonctions simples qui nous aideront à discuter de ces opérateurs en détail.

2. Dépendances Maven

Tout d'abord, nous devons ajouterRxJava2 etRxJava2Extensions comme dépendances Maven:


    io.reactivex.rxjava2
    rxjava
    2.2.2


    com.github.akarnokd
    rxjava2-extensions
    0.20.4

3. Les opérateurs

RxJava2 définita whole lot of operators pour divers cas d'utilisation de la programmation réactive.

Mais nous ne parlerons que de quelques opérateurs couramment utilisés pour convertir des méthodes synchrones ou asynchrones enObservables en fonction de leur nature. These operators take functions as arguments and emit the value returned from that function.

Avec les opérateurs normaux, RxJava2 définit quelques opérateurs supplémentaires pour des fonctionnalités étendues.

Voyons comment nous pouvons utiliser ces opérateurs pour convertir des méthodes synchrones et asynchrones.

4. Conversion de méthode synchrone

4.1. Utilisation defromCallable()

Cet opérateur renvoie unObservable qui, lorsqu'un abonné s'y abonne, invoque la fonction passée en argument puis émet la valeur renvoyée par cette fonction. Créons une fonction qui renvoie un entier et transforme-le:

AtomicInteger counter = new AtomicInteger();
Callable callable = () -> counter.incrementAndGet();

Maintenant, transformons-le enObservable et testons-le en vous y abonnant:

Observable source = Observable.fromCallable(callable);

for (int i = 1; i < 5; i++) {
    source.test()
      .awaitDone(5, TimeUnit.SECONDS)
      .assertResult(i);
    assertEquals(i, counter.get());
}

The fromCallable() operator executes the specified function lazily each time when the wrapped Observable gets subscribed. Pour tester ce comportement, nous avons créé plusieurs abonnés à l'aide d'une boucle.

Étant donné que les flux réactifs sont asynchrones par défaut, l’abonné reviendra immédiatement. Dans la plupart des scénarios pratiques, la fonction appelable aura une sorte de retard pour terminer son exécution. Donc,we’ve added a maximum wait time of five seconds avant de tester le résultat de notre fonction appelable.

Notez également que nous avons utilisé la méthodetest() deObservable. This method is handy when testing Observables. Il crée un sableTestObserver ouscrit à nosObservable.

4.2. Utilisation destart()

L'opérateurstart() fait partie du moduleRxJava2Extension. Il appellera la fonction spécifiée de manière asynchrone et retournera unObservable qui émettra le résultat:

Observable source = AsyncObservable.start(callable);

for (int i = 1; i < 5; i++) {
    source.test()
      .awaitDone(5, TimeUnit.SECONDS)
      .assertResult(1);
    assertEquals(1, counter.get());
}

La fonction est appelée immédiatement, pas à chaque fois qu'un abonné s'abonne auxObservable résultants. Multiple subscriptions to this observable observe the same return value.

5. Conversion de méthode asynchrone

5.1. Utilisation defromFuture()

Comme nous le savons, la manière la plus courante de créer une méthode asynchrone en Java consiste à utiliser l'implémentationFuture. La méthodefromFuture prend unFuture comme argument et émet la valeur obtenue à partir de la méthodeFuture.get().

Tout d'abord, rendons la fonction que nous avons créée précédemment asynchrone:

ExecutorService executor = Executors.newSingleThreadExecutor();
Future future = executor.submit(callable);

Ensuite, faisons le test en le transformant:

Observable source = Observable.fromFuture(future);

for (int i = 1; i < 5; i++) {
    source.test()
      .awaitDone(5, TimeUnit.SECONDS)
      .assertResult(1);
    assertEquals(1, counter.get());
}
executor.shutdown();

Et notez encore une fois que chaque abonnement observe la même valeur de retour.

Maintenant, la méthodedispose() deObservable est vraiment utile pour la prévention des fuites de mémoire. Mais dans ce cas, cela n'annulera pas le futur en raison de la nature bloquante deFuture.get().

Ainsi, nous pouvons nous assurer d'annuler le futur par la fonctioncombining the doOnDispose() de l'observablesource et la méthodecancel surfuture:

source.doOnDispose(() -> future.cancel(true));

5.2. Utilisation destartFuture()

Comme son nom l'indique, cet opérateur démarrera immédiatement lesFuture spécifiés et émettra la valeur de retour lorsqu'un abonné l'abonne. Contrairement à l'opérateurfromFuture qui met en cache le résultat pour une prochaine utilisation,this operator will execute the asynchronous method each time when it gets subscribed:

ExecutorService executor = Executors.newSingleThreadExecutor();
Observable source = AsyncObservable.startFuture(() -> executor.submit(callable));

for (int i = 1; i < 5; i++) {
    source.test()
      .awaitDone(5, TimeUnit.SECONDS)
      .assertResult(i);
    assertEquals(i, counter.get());
}
executor.shutdown();

5.3. Utilisation dedeferFuture()

This operator aggregates multiple Observables returned from a Future method and returns a stream of return values obtained from each Observable. Cela lancera la fonction d'usine asynchrone passée chaque fois qu'un nouvel abonné s'abonnera.

Commençons par créer la fonction de fabrique asynchrone:

List list = Arrays.asList(new Integer[] { counter.incrementAndGet(),
  counter.incrementAndGet(), counter.incrementAndGet() });
ExecutorService exec = Executors.newSingleThreadExecutor();
Callable> callable = () -> Observable.fromIterable(list);

Et puis on peut faire un test rapide:

Observable source = AsyncObservable.deferFuture(() -> exec.submit(callable));
for (int i = 1; i < 4; i++) {
    source.test()
      .awaitDone(5, TimeUnit.SECONDS)
      .assertResult(1,2,3);
}
exec.shutdown();

6. Conclusion

Dans ce didacticiel, nous avons appris à transformer les méthodes synchrones et asynchrones en observables RxJava2.

Bien entendu, les exemples que nous avons présentés ici sont les implémentations de base. Cependant, nous pouvons utiliser RxJava2 pour des applications plus complexes telles que la diffusion de vidéos en continu et les applications dans lesquelles nous devons envoyer de grandes quantités de données par portions.

Comme d'habitude, tous les courts exemples dont nous avons parlé ici se trouvent sur lesGithub project.