web-dev-qa-db-fra.com

Quelle est la différence entre flatmap et switchmap dans RxJava?

La définition de rxjava doc de switchmap est plutôt vague et renvoie au même page sous forme de flatmap. Quelle est la différence entre les deux opérateurs?

126
Julian Go

Selon la documentation ( http://reactivex.io/documentation/operators/flatmap.html )

la switchMap est semblable à la flatMap, mais elle émettra uniquement les éléments du nouvel observable jusqu'à ce qu'un nouvel événement soit émis à partir de la source observable.

Le diagramme en marbre le montre bien ... Notez la différence entre les diagrammes: 

Dans switchMap, la deuxième originale émission (marbre vert) n'émet pas sa deuxième cartographiée émission (carré vert), puisque la troisième original émission (marbre bleu) a commencé et a déjà émis sa première émission mappée (diamant bleu). En d’autres termes, seul le premier de deux cartographiées émissions vertes se produit; aucun carré vert n'est émis car le diamant bleu le bat.

Dans flatMap, tous les résultats cartographiés seront émis, même s'ils sont "périmés". En d'autres termes, les deux premiers et deuxièmes des cartographiées émissions vertes se produisent - un carré vert aurait été émis (s'ils avaient utilisé fonction de carte cohérente; comme ils ne l’ont pas fait, vous voyez le deuxième diamant vert, même s’il est émis après le premier diamant bleu)

switchMap in switchMap if the original observable emits something new, previous emissions no longer produce mapped observables; this is an effective way to avoid stale results

flatMap

 in switchMap if the original observable emits something new, previous emissions no longer produce mapped observables; this is an effective way to avoi stale results

153
dwursteisen

Je suis tombé sur cette information lors de la mise en oeuvre de la "recherche instantanée", c’est-à-dire lorsque l’utilisateur tapait dans une zone de texte et que les résultats apparaissaient presque en temps réel à chaque frappe. La solution semble être:

  1. Avoir un sujet, tel que PublishSubject of String
  2. Dans la zone de texte, rappel de rappel, appelez .onNext (text)
  3. appliquer un filtre .debounce pour évaluer le nombre de requêtes du serveur
  4. applique .switchMap pour effectuer une requête sur le serveur - prenant le terme de recherche et renvoyant Observable of SearchResponse
  5. appliquer .subscribe avec une méthode qui consomme SearchResponse et met à jour l'interface utilisateur.

Avec flatMap, les résultats de la recherche peuvent être obsolètes, car les réponses à la recherche risquent de ne plus être correctes. Pour résoudre ce problème, switchMap doit être utilisé, car il garantit qu’un ancien observable est désabonné une fois qu'un nouvel observateur est fourni.

Donc, en résumé, flatMap doit être utilisé lorsque tous les résultats importent, quel que soit le moment choisi, et switchMap doit être utilisé uniquement lorsque les résultats proviennent de la dernière matière Observable.

155
user4698855

Aucune discussion à plat n'est complète sans comparer et contraster avec switchMap, concatMap et concatMapEager.

Toutes ces méthodes prennent un Func1 qui transforme le flux en Observables qui sont ensuite émises; la différence correspond au moment où les Observables retournés sont abonnés et désabonnés, et si et quand, les émissions de ces Observables sont émises par l'opérateur ____Map en question.

  • flatMap souscrit à autant de Observables émis que possible. (Il s’agit d’un numéro dépendant de la plate-forme. Par exemple, un nombre inférieur sur Android). Utilisez cette option lorsque l’ordre n’est PAS important et que vous souhaitez des émissions dès que possible.
  • concatMap s'abonne à la première Observable et ne s'abonne qu'à la suivante Observable lorsque celle-ci est terminée. Utilisez cette option lorsque l'ordre est important et que vous souhaitez conserver les ressources. Un exemple parfait est le report d'un appel réseau en vérifiant d'abord le cache. Cela peut généralement être suivi d'une .first() ou d'une .takeFirst() afin d'éviter de faire un travail inutile.

    http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/

  • concatMapEager fonctionne à peu près de la même façon mais s’abonne au plus grand nombre (en fonction de la plate-forme) mais n’émet que lorsque le précédent Observable est terminé. Parfait lorsque vous devez effectuer beaucoup de traitements en parallèle, mais (contrairement à flatMap), vous souhaitez conserver la commande d'origine.

  • switchMap souscrira au dernier Observable rencontré et se désabonnera de tous les Observables précédents. Ceci est parfait pour les cas tels que les suggestions de recherche: une fois qu'un utilisateur a modifié sa requête de recherche, l'ancienne requête n'a plus aucun intérêt, elle est donc désabonnée et un noeud final Api bien tenu annule la requête réseau.

Si vous renvoyez Observables sans subscribeOn autre thread, toutes les méthodes ci-dessus peuvent se comporter sensiblement de la même manière. Le comportement intéressant et utile apparaît lorsque vous autorisez les Observables imbriqués à agir sur leurs propres threads. Vous pouvez alors tirer de nombreux avantages du traitement en parallèle et vous désabonner ou ne pas souscrire intelligemment auprès de Observables qui n'intéressent pas votre Subscribers

  • amb peut également présenter un intérêt. Quel que soit le nombre de Observables, il émet les mêmes éléments que le premier Observable pour émettre quoi que ce soit… .. Cela peut être utile lorsque vous avez plusieurs sources qui pourraient/devraient renvoyer la même chose et que vous voulez des performances. par exemple. amb peut être un tri rapide avec un tri par fusion et utiliser celui qui est le plus rapide.
79
Andrew Gallasch

switchMaps'appelait autrefoisflatMapLatest dans RxJS 4.

En gros, il ne fait que transmettre les événements du latest Observable et se désabonner du précédent.

50
Sentenza

Voici celui de plus - 101 lignes - exemple . Cela explique la chose pour moi.

Comme cela a été dit: il obtient la dernière observation (la plus lente si vous voulez) et ignore le reste.

Par conséquent:

Time | scheduler | state
----------------------------
0    | main      | Starting
84   | main      | Created
103  | main      | Subscribed
118  | Sched-C-0 | Going to emmit: A
119  | Sched-C-1 | Going to emmit: B
119  | Sched-C-0 | Sleep for 1 seconds for A
119  | Sched-C-1 | Sleep for 2 seconds for B
1123 | Sched-C-0 | Emitted (A) in 1000 milliseconds
2122 | Sched-C-1 | Emitted (B) in 2000 milliseconds
2128 | Sched-C-1 | Got B processed
2128 | Sched-C-1 | Completed

Vous voyez que le A a été ignoré.

0
ses

Si vous cherchez un exemple de code 

/**
 * We switch from original item to a new observable just using switchMap.
 * It´s a way to replace the Observable instead just the item as map does
 * Emitted:Person{name='Pablo', age=0, sex='no_sex'}
 */
@Test
public void testSwitchMap() {
    Observable.just(new Person("Pablo", 34, "male"))
              .switchMap(person -> Observable.just(new Person("Pablo", 0, "no_sex")))
              .subscribe(System.out::println);

}

Vous pouvez voir plus d'exemples ici https://github.com/politrons/reactive

0
paul