Introduction à RxRelay pour RxJava

Introduction à RxRelay pour RxJava

1. introduction

La popularité de RxJava a conduit à la création de plusieurs bibliothèques tierces qui étendent ses fonctionnalités.

Beaucoup de ces bibliothèques étaient une réponse aux problèmes typiques que rencontraient les développeurs lorsqu'ils utilisaient RxJava. RxRelay est l'une de ces solutions.

2. Traiter avec unSubject

En termes simples, unSubject agit comme un pont entreObservable etObserver. Puisqu'il s'agit d'unObserver, il peut s'abonner à un ou plusieursObservables et recevoir des événements de leur.

De plus, étant donné qu'il est en même temps unObservable, il peut réémettre des événements ou en émettre de nouveaux à ses abonnés. Plus d'informations sur lesSubject peuvent être trouvées dans cearticle.

L’un des problèmes avecSubject est qu’après avoir reçuonComplete() ouonError(), il ne peut plus déplacer de données. Parfois, c’est le comportement souhaité, mais parfois non.

Dans les cas où un tel comportement n'est pas souhaité, nous devrions envisager d'utiliserRxRelay.

3. Relay

UnRelay est fondamentalement unSubject, mais sans la possibilité d'appeleronComplete() etonError(),, il est donc constamment capable d'émettre des données.

Cela nous permet de créer des ponts entre différents types d’API sans craindre de déclencher accidentellement l’état du terminal.

Pour utiliserRxRelay, nous devons ajouter la dépendance suivante à notre projet:


  com.jakewharton.rxrelay2
  rxrelay
  1.2.0

4. Types deRelay

Il existe trois types différents deRelay disponibles dans la bibliothèque. Nous allons rapidement explorer les trois ici.

4.1. PublishRelay

Ce type deRelay réémettra tous les événements une fois que leObserver y sera abonné.

Les événements seront émis à tous les abonnés:

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

Il n'y a pas de mise en mémoire tampon des événements dans ce cas, donc ce comportement est similaire à unObservable. froid

4.2. BehaviorRelay

Ce type deRelay réémettra l'événement observé le plus récent et tous les événements suivants une fois que le Observer aura souscrit:

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

Lorsque nous créons lesBehaviorRelay, nous pouvons spécifier la valeur par défaut, qui sera émise s'il n'y a pas d'autres événements à émettre.

Pour spécifier la valeur par défaut, nous pouvons utiliser la méthodecreateDefault():

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

Si nous ne voulons pas spécifier la valeur par défaut, nous pouvons utiliser la méthodecreate():

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

4.3. ReplayRelay

Ce type deRelay met en mémoire tampon tous les événements qu'il a reçus, puis les réémet à tous les abonnés qui s'y abonnent:

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

Tous les éléments sont mis en mémoire tampon et tous les abonnés recevront les mêmes événements, doncthis behavior is similar to the cold Observable.

Lorsque nous créons lesReplayRelay, nous pouvons fournir une taille de tampon et une durée de vie maximales pour les événements.

Pour créer lesRelay avec une taille de tampon limitée, nous pouvons utiliser la méthodecreateWithSize(). Lorsqu'il y a plus d'événements à mettre en mémoire tampon que la taille de tampon définie, les éléments précédents sont supprimés:

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

Nous pouvons également créer desReplayRelay avec le temps maximum de sortie pour les événements mis en mémoire tampon en utilisant la méthodecreateWithTime():

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. PersonnaliséRelay

Tous les types décrits ci-dessus étendent la classe abstraite communeRelay,, ce qui nous donne la possibilité d'écrire notre propre classeRelay personnalisée.

Pour créer unRelay personnalisé, nous devons implémenter trois méthodes:accept(), hasObservers() etsubscribeActual().

Écrivons un simple relais qui réémettra l'événement à l'un des abonnés choisis au hasard:

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

Nous pouvons maintenant tester qu'un seul abonné recevra l'événement:

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

Dans ce tutoriel, nous avons examiné RxRelay, un type similaire àSubject mais sans possibilité de déclencher l'état du terminal.

Plus d'informations peuvent être trouvées dans lesdocumentation. Et, comme toujours, tous les exemples de code peuvent être trouvésover on GitHub.