web-dev-qa-db-fra.com

Obtenez la dernière valeur d'un observable et émettez-le immédiatement

J'essaie d'obtenir la dernière valeur d'une Observable donnée et de la faire émettre Immédiatement après l'appel. En prenant le code ci-dessous à titre d'exemple:

return Observable.just(myObservable.last())
    .flatMap(myObservable1 -> {
        return myObservable1;
    })
    .map(o -> o.x) // Here I want to end up with a T object instead of Observable<T> object

Cela ne fonctionne pas car en faisant cela, la flatMap émettra myObservable1 qui devra à son tour émettre pour atteindre la map. Je ne sais pas si cela est même possible. Quelqu'un at-il une idée sur la façon d'atteindre cet objectif? Je vous remercie

10
E-Kami

La méthode last() ne vous sera d'aucune aide car elle attend la fin de l'observable pour vous donner le dernier élément émis.

En supposant que vous n’ayez pas le contrôle sur l’observable émetteur, vous pouvez simplement créer un BehaviorSubject et le souscrire à l’observable qui émet les données que vous souhaitez écouter, puis vous abonner au sujet créé. Puisque Subject est à la fois Observable et Subscriber, vous obtiendrez ce que vous voulez. 

Je pense que (vous n'avez pas le temps de le vérifier maintenant), vous devrez peut-être vous désinscrire manuellement de l'observable d'origine sous le nom BehaviorSubject une fois que tous ses abonnés se désabonnant ne se désabonneront pas automatiquement. 

Quelque chose comme ça:

BehaviorSubject subject = new BehaviorSubject();
hotObservable.subscribe(subject);
subject.subscribe(thing -> {
    // Here just after subscribing 
    // you will receive the last emitted item, if there was any.
    // You can also always supply the first item to the behavior subject
});

http://reactivex.io/RxJava/javadoc/rx/subjects/BehaviorSubject.html

21
MatBos

Dans RxJava, subscriber.onXXX est appelé asynchrone. Cela signifie que si votre observable émet des éléments dans un nouveau fil, vous ne pouvez jamais obtenir le dernier élément avant le renvoi, sauf si vous bloquez le fil et attendez l'élément. et vous ne changez pas son thread par subscribeOn et observOn, comme le code:

Observable.just(1,2,3).subscribe();

Dans ce cas, vous pouvez obtenir le dernier élément en procédant comme suit:

Integer getLast(Observable<Integer> o){
    final int[] ret = new int[1];
    Observable.last().subscribe(i -> ret[0] = i);
    return ret[0];
}

C'est une mauvaise idée de procéder ainsi. RxJava préfère que vous fassiez un travail asynchrone.

1
dieyidezui

Ce que vous voulez réellement réaliser ici est de transformer une tâche asynchrone en tâche synchrone. 

Il y a plusieurs façons d'y parvenir, chacune avec ses avantages et ses inconvénients:

  • Utilisez toBlocking () - cela signifie que ce fil sera BLOQUÉ jusqu'à la fin du flux. Afin d'obtenir un seul élément, utilisez simplement first () car il se terminera une fois qu'un élément est livré. Supposons que votre flux entier est Observable<T> getData(); Une méthode qui obtiendra immédiatement la dernière valeur ressemblera à ceci:

public T getLastItem(){ return getData().toBlocking().first(); }

veuillez ne pas utiliser last () car il attendra que le flux soit complet et seulement à ce moment-là émettra le dernier élément.

Si votre flux est une requête réseau et qu'il n'a pas encore reçu d'élément, cela bloquera votre thread!, Utilisez-le uniquement si vous êtes sûr qu'un élément est disponible immédiatement (ou si vous voulez vraiment un blocage ...)

  • une autre option consiste à simplement mettre en cache le dernier résultat, quelque chose comme ceci:

    getData (). subscribe (t-> cachedT = t;) // quelque part dans le code et continuera à enregistrer le dernier élément livré public T getLastItem () { return cachedT; }

si aucun élément n'a été envoyé au moment où vous le demandez, vous obtiendrez la valeur null ou la valeur initiale que vous avez définie .. Le problème avec cette approche est que la phase d'abonnement peut se produire après l'obtention et peut créer une condition de concurrence critique si utilisé dans 2 threads différents.

0
ndori