RxJava 2 - Fluide

RxJava 2 - Fluide

1. introduction

RxJava is a Reactive Extensions Java implementation that allows us to write event-driven, and asynchronous applications. Plus d'informations sur l'utilisation de RxJava peuvent être trouvées dans nosintro article here.

RxJava 2 a été réécrit à partir de zéro, ce qui a apporté de nombreuses nouvelles fonctionnalités. dont certaines ont été créées pour répondre à des problèmes qui existaient dans la version précédente du cadre.

L'une de ces caractéristiques est leio.reactivex.Flowable.

2. Observable contre. Flowable

Dans la version précédente de RxJava, il n'y avait qu'une seule classe de base pour traiter les sources sensibles à la contre-pression et non sensibles à la contre-pression -Observable.

RxJava 2 a introduit une distinction claire entre ces deux types de sources - les sources sensibles à la contre-pression sont maintenant représentées à l'aide d'une classe dédiée -Flowable.

Les sources deObservablene prennent pas en charge la contre-pression. Pour cette raison, nous devons l'utiliser pour des sources que nous consommons simplement et que nous ne pouvons pas influencer.

De plus, si nous avons affaire à un grand nombre d’éléments, deux scénarios possibles liés àbackpressure peuvent se produire selon le type desObservable.

En cas d'utilisation d'un soi-disantgrondement, les événements deObservable“,ont émis paresseusement, nous sommes donc à l'abri de débordement d'observateur.

Cependant, lorsque vous utilisez un tirObservable, cela continuera à émettre des événements, même si le consommateur ne peut pas suivre.

3. Créer unFlowable

Il existe différentes manières de créer unFlowable. Pour nous, ces méthodes ressemblent aux méthodes deObservable de la première version de RxJava.

3.1. Flowable simples

Nous pouvons créer unFlowable en utilisant la méthodejust() de la même manière que nous le pourrions avecObservable :

Flowable integerFlowable = Flowable.just(1, 2, 3, 4);

Même si l’utilisation desjust() est assez simple, il n’est pas très courant de créer desFlowable à partir de données statiques, et elles sont utilisées à des fins de test.

3.2. Flowable à partir deObservable

When we have an Observable we can easily transform it to Flowable using the toFlowable() method:

Observable integerObservable = Observable.just(1, 2, 3);
Flowable integerFlowable = integerObservable
  .toFlowable(BackpressureStrategy.BUFFER);

Notez que pour pouvoir effectuer la conversion, nous devons enrichir lesObservable avec unBackpressureStrategy.. Nous allons décrire les stratégies disponibles dans la section suivante.

3.3. Flowable à partir deFlowableOnSubscribe

RxJava 2 a introduit une interface fonctionnelleFlowableOnSubscribe, qui représente unFlowable qui commence à émettre des événements une fois que le consommateur s'y est abonné.

Pour cette raison, tous les clients recevront le même ensemble d'événements, ce qui rendFlowableOnSubscribe sans contre-pression.

Lorsque nous avons lesFlowableOnSubscribe, nous pouvons l'utiliser pour créer lesFlowable:

FlowableOnSubscribe flowableOnSubscribe
 = flowable -> flowable.onNext(1);
Flowable integerFlowable = Flowable
  .create(flowableOnSubscribe, BackpressureStrategy.BUFFER);

La documentation décrit de nombreuses autres méthodes pour créer desFlowable.

4. FlowableBackpressureStrategy

Certaines méthodes commetoFlowable() oucreate() prennent unBackpressureStrategy comme argument.

LeBackpressureStrategy est une énumération, qui définit le comportement de contre-pression que nous appliquerons à notre Fluide.

Il peut mettre en cache ou supprimer des événements ou ne pas appliquer de comportement du tout. Dans le dernier cas, nous serons responsables de le définir, à l'aide d'opérateurs de contre-pression.

BackpressureStrategy est similaire àBackpressureMode présent dans la version précédente de RxJava.

Il existe cinq stratégies différentes disponibles dans RxJava 2.

4.1. Tampon

If we use the BackpressureStrategy.BUFFER, the source will buffer all the events until the subscriber can consume them:

public void thenAllValuesAreBufferedAndReceived() {
    List testList = IntStream.range(0, 100000)
      .boxed()
      .collect(Collectors.toList());

    Observable observable = Observable.fromIterable(testList);
    TestSubscriber testSubscriber = observable
      .toFlowable(BackpressureStrategy.BUFFER)
      .observeOn(Schedulers.computation()).test();

    testSubscriber.awaitTerminalEvent();

    List receivedInts = testSubscriber.getEvents()
      .get(0)
      .stream()
      .mapToInt(object -> (int) object)
      .boxed()
      .collect(Collectors.toList());

    assertEquals(testList, receivedInts);
}

Cela revient à appeler la méthodeonBackpressureBuffer() surFlowable, mais cela ne permet pas de définir explicitement une taille de tampon ou l’action onOverflow.

4.2. Drop

Nous pouvons utiliser lesBackpressureStrategy.DROP pour ignorer les événements qui ne peuvent pas être consommés au lieu de les mettre en mémoire tampon.

Encore une fois, cela revient à utiliseronBackpressureDrop() surFlowable:

public void whenDropStrategyUsed_thenOnBackpressureDropped() {

    Observable observable = Observable.fromIterable(testList);
    TestSubscriber testSubscriber = observable
      .toFlowable(BackpressureStrategy.DROP)
      .observeOn(Schedulers.computation())
      .test();
    testSubscriber.awaitTerminalEvent();
    List receivedInts = testSubscriber.getEvents()
      .get(0)
      .stream()
      .mapToInt(object -> (int) object)
      .boxed()
      .collect(Collectors.toList());

    assertThat(receivedInts.size() < testList.size());
    assertThat(!receivedInts.contains(100000));
 }

4.3. Dernier

L'utilisation desBackpressureStrategy.LATEST forcera la source à ne conserver que les derniers événements, écrasant ainsi toutes les valeurs précédentes si le consommateur ne peut pas suivre:

public void whenLatestStrategyUsed_thenTheLastElementReceived() {

    Observable observable = Observable.fromIterable(testList);
    TestSubscriber testSubscriber = observable
      .toFlowable(BackpressureStrategy.LATEST)
      .observeOn(Schedulers.computation())
      .test();

    testSubscriber.awaitTerminalEvent();
    List receivedInts = testSubscriber.getEvents()
      .get(0)
      .stream()
      .mapToInt(object -> (int) object)
      .boxed()
      .collect(Collectors.toList());

    assertThat(receivedInts.size() < testList.size());
    assertThat(receivedInts.contains(100000));
 }

LesBackpressureStrategy.LATEST and BackpressureStrategy.DROP sont très similaires lorsque nous regardons le code.

Cependant,BackpressureStrategy.LATEST écrasera les éléments que notre abonné ne peut pas gérer et ne conservera que les derniers, d'où le nom.

BackpressureStrategy.DROP,, par contre, supprimera les éléments qui ne peuvent pas être traités. Cela signifie que les éléments les plus récents ne seront pas nécessairement émis.

4.4. Erreur

Lorsque nous utilisons lesBackpressureStrategy.ERROR,, nous disons simplement quewe don’t expect backpressure to occur. Par conséquent, unMissingBackpressureException doit être lancé si le consommateur ne peut pas suivre la source:

public void whenErrorStrategyUsed_thenExceptionIsThrown() {
    Observable observable = Observable.range(1, 100000);
    TestSubscriber subscriber = observable
      .toFlowable(BackpressureStrategy.ERROR)
      .observeOn(Schedulers.computation())
      .test();

    subscriber.awaitTerminalEvent();
    subscriber.assertError(MissingBackpressureException.class);
}

4.5. Disparu

Si nous utilisons lesBackpressureStrategy.MISSING, la source poussera les éléments sans rejet ni mise en mémoire tampon.

L'aval devra faire face à des débordements dans ce cas:

public void whenMissingStrategyUsed_thenException() {
    Observable observable = Observable.range(1, 100000);
    TestSubscriber subscriber = observable
      .toFlowable(BackpressureStrategy.MISSING)
      .observeOn(Schedulers.computation())
      .test();
    subscriber.awaitTerminalEvent();
    subscriber.assertError(MissingBackpressureException.class);
}

Dans nos tests, nous excluonsMissingbackpressureException pour les stratégiesERROR etMISSING. Comme tous les deux lèveront une telle exception lorsque le tampon interne de la source est dépassé.

Cependant, il convient de noter que les deux ont un objectif différent.

Nous devrions utiliser l'ancien lorsque nous ne nous attendons pas du tout à une contre-pression, et nous voulons que la source lève une exception au cas où elle se produirait.

Ce dernier peut être utilisé si nous ne voulons pas spécifier un comportement par défaut lors de la création desFlowable. Et nous allons utiliser des opérateurs de contre-pression pour le définir plus tard.

5. Sommaire

Dans ce didacticiel, nous avons présenté la nouvelle classe introduite dans RxJava2 appeléeFlowable.

Pour trouver plus d'informations sur leFlowable lui-même et son API, nous pouvons nous référer auxdocumentation.

Comme toujours, tous les échantillons de code peuvent être trouvésover on GitHub.