Einführung in RxRelay für RxJava

Einführung in RxRelay für RxJava

1. Einführung

Die Popularität von RxJava hat zur Schaffung mehrerer Bibliotheken von Drittanbietern geführt, die die Funktionalität erweitern.

Viele dieser Bibliotheken waren eine Antwort auf typische Probleme, mit denen Entwickler bei der Verwendung von RxJava zu kämpfen hatten. RxRelay ist eine dieser Lösungen.

2. Umgang mit aSubject

Einfach ausgedrückt, einSubject fungiert als Brücke zwischenObservable undObserver. Da es sich um einObserver handelt, kann es ein oder mehrereObservables abonnieren und Ereignisse von empfangen Sie.

Da es gleichzeitig einObservable ist, kann es Ereignisse erneut auslösen oder neue Ereignisse an seine Abonnenten senden. Weitere Informationen zuSubject finden Sie inarticle.

Eines der Probleme mitSubject besteht darin, dass nach dem Empfang vononComplete() oderonError() keine Daten mehr verschoben werden können. Manchmal ist es das gewünschte Verhalten, manchmal nicht.

In Fällen, in denen ein solches Verhalten nicht erwünscht ist, sollten wir die Verwendung vonRxRelay in Betracht ziehen.

3. Relay

EinRelay ist im Grunde einSubject, aber ohne die Möglichkeit,onComplete() undonError(), aufzurufen, kann es ständig Daten ausgeben.

Auf diese Weise können wir Brücken zwischen verschiedenen API-Typen erstellen, ohne versehentlich den Terminalstatus auslösen zu müssen.

UmRxRelay zu verwenden, müssen wir unserem Projekt die folgende Abhängigkeit hinzufügen:


  com.jakewharton.rxrelay2
  rxrelay
  1.2.0

4. Arten vonRelay

In der Bibliothek stehen drei verschiedene Arten vonRelayzur Verfügung. Wir werden alle drei hier schnell erkunden.

4.1. PublishRelay

Diese Art vonRelay beendet alle Ereignisse erneut, sobaldObserver sie abonniert hat.

Die Ereignisse werden an alle Abonnenten gesendet:

public void whenObserverSubscribedToPublishRelay_itReceivesEmittedEvents() {
    PublishRelay publishRelay = PublishRelay.create();
    TestObserver firstObserver = TestObserver.create();
    TestObserver secondObserver = TestObserver.create();

    publishRelay.subscribe(firstObserver);
    firstObserver.assertSubscribed();
    publishRelay.accept(5);
    publishRelay.accept(10);
    publishRelay.subscribe(secondObserver);
    secondObserver.assertSubscribed();
    publishRelay.accept(15);
    firstObserver.assertValues(5, 10, 15);

    // second receives only the last event
    secondObserver.assertValue(15);
}

In diesem Fall erfolgt keine Pufferung von Ereignissen, daher ähnelt dieses Verhalten einem kaltenObservable.

4.2. BehaviorRelay

Diese Art vonRelay gibt das zuletzt beobachtete Ereignis und alle nachfolgenden Ereignisse wieder frei, sobald die Observer abonniert haben:

public void whenObserverSubscribedToBehaviorRelay_itReceivesEmittedEvents() {
    BehaviorRelay behaviorRelay = BehaviorRelay.create();
    TestObserver firstObserver = TestObserver.create();
    TestObserver secondObserver = TestObserver.create();
    behaviorRelay.accept(5);
    behaviorRelay.subscribe(firstObserver);
    behaviorRelay.accept(10);
    behaviorRelay.subscribe(secondObserver);
    behaviorRelay.accept(15);
    firstObserver.assertValues(5, 10, 15);
    secondObserver.assertValues(10, 15);
}

Beim Erstellen derBehaviorRelay können wir den Standardwert angeben, der ausgegeben wird, wenn keine anderen Ereignisse ausgegeben werden sollen.

Um den Standardwert anzugeben, können wir die MethodecreateDefault()verwenden:

public void whenObserverSubscribedToBehaviorRelay_itReceivesDefaultValue() {
    BehaviorRelay behaviorRelay = BehaviorRelay.createDefault(1);
    TestObserver firstObserver = new TestObserver<>();
    behaviorRelay.subscribe(firstObserver);
    firstObserver.assertValue(1);
}

Wenn wir den Standardwert nicht angeben möchten, können wir die Methodecreate()verwenden:

public void whenObserverSubscribedToBehaviorRelayWithoutDefaultValue_itIsEmpty() {
    BehaviorRelay behaviorRelay = BehaviorRelay.create();
    TestObserver firstObserver = new TestObserver<>();
    behaviorRelay.subscribe(firstObserver);
    firstObserver.assertEmpty();
}

4.3. ReplayRelay

Diese Art vonRelay puffert alle empfangenen Ereignisse und sendet sie dann an alle Abonnenten weiter, die sie abonniert haben:

 public void whenObserverSubscribedToReplayRelay_itReceivesEmittedEvents() {
    ReplayRelay replayRelay = ReplayRelay.create();
    TestObserver firstObserver = TestObserver.create();
    TestObserver secondObserver = TestObserver.create();
    replayRelay.subscribe(firstObserver);
    replayRelay.accept(5);
    replayRelay.accept(10);
    replayRelay.accept(15);
    replayRelay.subscribe(secondObserver);
    firstObserver.assertValues(5, 10, 15);
    secondObserver.assertValues(5, 10, 15);
}

Alle Elemente werden gepuffert und alle Teilnehmer erhalten die gleichen Ereignisse, alsothis behavior is similar to the cold Observable.

Wenn wirReplayRelay erstellen, können wir die maximale Puffergröße und die maximale Lebensdauer für Ereignisse angeben.

UmRelay mit begrenzter Puffergröße zu erstellen, können Sie die MethodecreateWithSize() verwenden. Wenn mehr Ereignisse als die festgelegte Puffergröße gepuffert werden müssen, werden vorherige Elemente verworfen:

public void whenObserverSubscribedToReplayRelayWithLimitedSize_itReceivesEmittedEvents() {
    ReplayRelay replayRelay = ReplayRelay.createWithSize(2);
    TestObserver firstObserver = TestObserver.create();
    replayRelay.accept(5);
    replayRelay.accept(10);
    replayRelay.accept(15);
    replayRelay.accept(20);
    replayRelay.subscribe(firstObserver);
    firstObserver.assertValues(15, 20);
}

Mit der MethodecreateWithTime() können wir auchReplayRelay mit maximaler Zeit für gepufferte Ereignisse erstellen:

public void whenObserverSubscribedToReplayRelayWithMaxAge_thenItReceivesEmittedEvents() {
    SingleScheduler scheduler = new SingleScheduler();
    ReplayRelay replayRelay =
      ReplayRelay.createWithTime(2000, TimeUnit.MILLISECONDS, scheduler);
    long current =  scheduler.now(TimeUnit.MILLISECONDS);
    TestObserver firstObserver = TestObserver.create();
    replayRelay.accept(5);
    replayRelay.accept(10);
    replayRelay.accept(15);
    replayRelay.accept(20);
    Thread.sleep(3000);
    replayRelay.subscribe(firstObserver);
    firstObserver.assertEmpty();
}

5. BenutzerdefinierteRelay

Alle oben beschriebenen Typen erweitern die gemeinsame abstrakte KlasseRelay,. Dies gibt uns die Möglichkeit, unsere eigene benutzerdefinierte KlasseRelayzu schreiben.

Um ein benutzerdefiniertesRelay zu erstellen, müssen drei Methoden implementiert werden:accept(), hasObservers() undsubscribeActual().

Schreiben wir ein einfaches Relais, das das Ereignis an einen der zufällig ausgewählten Abonnenten zurücksendet:

public class RandomRelay extends Relay {
    Random random = new Random();

    List> observers = new ArrayList<>();

    @Override
    public void accept(Integer integer) {
        int observerIndex = random.nextInt() % observers.size();
        observers.get(observerIndex).onNext(integer);
    }

    @Override
    public boolean hasObservers() {
        return observers.isEmpty();
    }

    @Override
    protected void subscribeActual(Observer observer) {
        observers.add(observer);
        observer.onSubscribe(Disposables.fromRunnable(
          () -> System.out.println("Disposed")));
    }
}

Wir können jetzt testen, ob nur ein Teilnehmer das Ereignis empfängt:

public void whenTwoObserversSubscribedToRandomRelay_thenOnlyOneReceivesEvent() {
    RandomRelay randomRelay = new RandomRelay();
    TestObserver firstObserver = TestObserver.create();
    TestObserver secondObserver = TestObserver.create();
    randomRelay.subscribe(firstObserver);
    randomRelay.subscribe(secondObserver);
    randomRelay.accept(5);
    if(firstObserver.values().isEmpty()) {
        secondObserver.assertValue(5);
    } else {
        firstObserver.assertValue(5);
        secondObserver.assertEmpty();
    }
}

6. Fazit

In diesem Tutorial haben wir uns RxRelay angesehen, einen Typ ähnlichSubject, jedoch ohne die Möglichkeit, den Terminalstatus auszulösen.

Weitere Informationen finden Sie indocumentation. Und wie immer finden sich alle Codebeispiele inover on GitHub.