RxJava 2 - fließfähig

RxJava 2 - Fließfähig

1. Einführung

RxJava is a Reactive Extensions Java implementation that allows us to write event-driven, and asynchronous applications. Weitere Informationen zur Verwendung von RxJava finden Sie in unserenintro article here.

RxJava 2 wurde von Grund auf neu geschrieben, was mehrere neue Funktionen mit sich brachte. Einige davon wurden als Antwort auf Probleme in der vorherigen Version des Frameworks erstellt.

Eines dieser Merkmale istio.reactivex.Flowable.

2. Observable vs. Flowable

In der vorherigen Version von RxJava gab es nur eine Basisklasse für den Umgang mit Quellen, die dem Gegendruck bewusst sind und nicht dem Gegendruck bewusst sind -Observable.

RxJava 2 führte eine klare Unterscheidung zwischen diesen beiden Arten von Quellen ein - Quellen, die dem Gegendruck bewusst sind, werden jetzt mit einer dedizierten Klasse dargestellt -Flowable.

Die Quellen vonObservableunterstützen keinen Gegendruck. Aus diesem Grund sollten wir es für Quellen verwenden, die wir lediglich konsumieren und die wir nicht beeinflussen können.

Wenn es sich um eine große Anzahl von Elementen handelt, können je nach Art derObservable zwei mögliche Szenarien auftreten, die mitbackpressure verbunden sind.

Bei Verwendung eines sogenannten-Schimpfs werdenObservable“,-Ereignisse träge ausgegeben, sodass wir sicher sind, dass ein Beobachter nicht überläuft.

Bei Verwendung eines-SchussesObservable werden jedoch weiterhin Ereignisse ausgegeben, auch wenn der Verbraucher nicht mithalten kann.

3. Flowable erstellen

Es gibt verschiedene Möglichkeiten, einFlowablezu erstellen. Praktischerweise ähneln diese Methoden den Methoden inObservable in der ersten Version von RxJava.

3.1. EinfacheFlowable

Wir könnenFlowable mit der Methodejust() erstellen, ähnlich wie wir es mitObservable : tun könnten

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

Obwohl die Verwendung vonjust() recht einfach ist, ist es nicht sehr üblich,Flowable aus statischen Daten zu erstellen, und sie werden zu Testzwecken verwendet.

3.2. Flowable vonObservable

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

Beachten Sie, dass wir dieObservable mitBackpressureStrategy. anreichern müssen, um die Konvertierung durchführen zu können. Die verfügbaren Strategien werden im nächsten Abschnitt beschrieben.

3.3. Flowable vonFlowableOnSubscribe

RxJava 2 hat eine funktionale SchnittstelleFlowableOnSubscribe eingeführt, dieFlowable darstellt und Ereignisse ausgibt, nachdem der Verbraucher sie abonniert hat.

Aus diesem Grund erhalten alle Clients die gleichen Ereignisse, wodurch der Gegendruck vonFlowableOnSubscribeicher ist.

Wenn wir dieFlowableOnSubscribe haben, können wir damit dieFlowable erstellen:

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

In der Dokumentation werden viele weitere Methoden zum Erstellen vonFlowable. beschrieben

4. FlowableBackpressureStrategy

Einige Methoden wietoFlowable() odercreate() verwendenBackpressureStrategy als Argument.

DasBackpressureStrategy ist eine Aufzählung, die das Gegendruckverhalten definiert, das wir auf unser anwenden werden Fließfähig.

Es kann Ereignisse zwischenspeichern oder löschen oder überhaupt kein Verhalten implementieren. In letzterem Fall sind wir dafür verantwortlich, es mithilfe von Rückstauoperatoren zu definieren.

BackpressureStrategy ähneltBackpressureMode in der vorherigen Version von RxJava.

In RxJava 2 stehen fünf verschiedene Strategien zur Verfügung.

4.1. Puffer

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

Es ähnelt dem Aufrufen deronBackpressureBuffer()-Methode fürFlowable,, erlaubt jedoch nicht, eine Puffergröße oder die onOverflow-Aktion explizit zu definieren.

4.2. Drop

Wir könnenBackpressureStrategy.DROP verwenden, um die Ereignisse zu verwerfen, die nicht verbraucht werden können, anstatt sie zu puffern.

Dies ähnelt wiederum der Verwendung vononBackpressureDrop() aufFlowable:

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. Neueste

Die Verwendung vonBackpressureStrategy.LATEST zwingt die Quelle, nur die neuesten Ereignisse beizubehalten, wodurch alle vorherigen Werte überschrieben werden, wenn der Verbraucher nicht mithalten kann:

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

BackpressureStrategy.LATEST and BackpressureStrategy.DROP sehen sehr ähnlich aus, wenn wir uns den Code ansehen.

BackpressureStrategy.LATEST überschreibt jedoch Elemente, die unser Abonnent nicht verarbeiten kann, und behält nur die neuesten, daher der Name.

BackpressureStrategy.DROP, hingegen verwirft Elemente, die nicht verarbeitet werden können. Dies bedeutet, dass die neuesten Elemente nicht unbedingt ausgegeben werden.

4.4. Error

Wenn wirBackpressureStrategy.ERROR, verwenden, sagen wir einfachwe don’t expect backpressure to occur. Folglich sollte einMissingBackpressureException geworfen werden, wenn der Verbraucher nicht mit der Quelle Schritt halten kann:

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. Vermisst

Wenn wirBackpressureStrategy.MISSING verwenden, pusht die Quelle Elemente, ohne sie zu verwerfen oder zu puffern.

Der Downstream muss sich in diesem Fall mit Überläufen befassen:

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

In unseren Tests schließen wirMissingbackpressureException sowohl fürERROR als auch fürMISSING Strategien aus. Da beide eine solche Ausnahme auslösen, wenn der interne Puffer der Quelle überfüllt ist.

Es ist jedoch anzumerken, dass beide einen unterschiedlichen Zweck haben.

Wir sollten den ersteren verwenden, wenn wir überhaupt keinen Gegendruck erwarten, und wir möchten, dass die Quelle eine Ausnahme auslöst, falls er auftritt.

Letzteres kann verwendet werden, wenn beim Erstellen derFlowable kein Standardverhalten angegeben werden soll. Und wir werden später Gegendruckoperatoren verwenden, um es zu definieren.

5. Zusammenfassung

In diesem Tutorial haben wir die neue Klasse vorgestellt, die in RxJava2 mit dem NamenFlowable. eingeführt wurde

Weitere Informationen zuFlowable selbst und seiner API finden Sie unterdocumentation.

Wie immer finden sich alle Codebeispiele inover on GitHub.