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

149

La définition rxjava doc de switchmap est assez vague et renvoie à la même page que flatmap. Quelle est la différence entre les deux opérateurs?

Julian Go
la source
1
À ce sujet , des liens vers la même page que flatmap . C'est vraiment vrai. Mais faites défiler jusqu'à la section Informations spécifiques à la langue et ouvrez l'opérateur intéressant. Je pense que cela devrait être fait automatiquement à partir de la table des matières, mais ... Vous pouvez également voir la même image dans javadoc .
Ruslan Stelmachenko

Réponses:

180

D'après la documentation ( http://reactivex.io/documentation/operators/flatmap.html )

le switchMapest comme le flatMap, mais il n'émettra que des éléments de la nouvelle observable jusqu'à ce qu'un nouvel événement soit émis par l'observable source.

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

Dans switchMapla deuxième émission d' origine ( marbre vert ) n'émet pas sa deuxième émission cartographiée ( carré vert ), puisque la troisième émission d' origine ( marbre bleu ) a commencé et a déjà émis sa première émission cartographiée ( diamant bleu ). En d'autres termes, seule la première des deux émissions vertes cartographiées se produit; aucun carré vert n'est émis car le diamant bleu l'a battu.

Dans flatMap, tous les résultats mappés seront émis, même s'ils sont "périmés". En d'autres termes, le premier et le deuxième des émissions vertes cartographiées se produisent - un carré vert aurait été émis (s'ils utilisaient une fonction de carte cohérente; puisqu'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 dans switchMap si l'observable d'origine émet quelque chose de nouveau, les émissions précédentes ne produisent plus d'observables cartographiés;  c'est un moyen efficace d'éviter les résultats périmés

flatMap

dans switchMap si l'observable d'origine émet quelque chose de nouveau, les émissions précédentes ne produisent plus d'observables cartographiés;  c'est un moyen efficace d'éviter les résultats périmés

dwursteisen
la source
4
Merci, le diagramme est très utile. Connaissez-vous un exemple concret où switchMap serait utilisé?
Julian Go
1
@JulianGo il y a un exemple ici: github.com/samuelgruetter/rx-playground/blob/master/… Il utilise .map(func).switch, mais c'est la même chose que .switchMap(func).
Samuel Gruetter
2
Juste au cas où quelqu'un aurait encore besoin d'un exemple réel de switchMap, il peut suivre ce lien et il comprendra quand utiliser swicthMap au lieu de flatMap.
hermannovich
2
Pour un exemple utilisant SwitchMap de Ben Lesh utilisant RxJs5 - voir les minutes 25-26 ici - youtube.com/watch?v=3LKMwkuK0ZE pour moi, flatmap était déjà compris ...
arcseldon
7
Le diagramme en marbre le montre bien? Quoi? Je suppose que si vous comprenez déjà Switchmap peut-être.
Helzgate
166

Je suis tombé sur cela lors de la mise en œuvre de la "recherche instantanée" - c'est-à-dire lorsque l'utilisateur tape dans une zone de texte et que les résultats apparaissent presque en temps réel à chaque coup de touche. La solution semble être:

  1. Avoir un sujet, tel que PublishSubject of String
  2. Dans la zone de texte, appelez le rappel de modification, appelez .onNext (texte)
  3. appliquer le filtre .debounce pour évaluer les requêtes de serveur de limite
  4. appliquer .switchMap pour effectuer une requête serveur - prendre le terme de recherche et renvoyer Observable de SearchResponse
  5. apply .subscribe avec une méthode qui utilise SearchResponse et met à jour l'interface utilisateur.

Avec flatMap, les résultats de la recherche peuvent être obsolètes, car les réponses de recherche peuvent revenir dans le désordre. Pour résoudre ce problème, switchMap doit être utilisé, car il garantit qu'une ancienne observable est désabonnée une fois qu'une plus récente est fournie.

Donc, en résumé, flatMap doit être utilisé lorsque tous les résultats comptent, quel que soit leur timing, et switchMap doit être utilisé lorsque seuls les résultats de la dernière matière observable.

user4698855
la source
Vous pouvez consulter cet exemple dans GitHub
Cabezas
95

Aucune discussion flatMap n'est complète sans comparaison et contraste avec switchMap, concatMapet concatMapEager.

Toutes ces méthodes prennent un Func1qui transforme le flux en Observables qui sont ensuite émis; la différence est lorsque les Observables retournés sont souscrits et désabonnés, et si et quand ceux-ci les émissions de ces Observables sont émises par l' ____Mapopérateur en question.

  • flatMapsouscrit à autant d'émissions Observableque possible. (C'est un numéro dépendant de la plate-forme. Par exemple, un nombre inférieur sur Android) Utilisez-le lorsque la commande n'est PAS importante et que vous voulez des émissions dès que possible.
  • concatMapsouscrit au premier Observableet ne souscrit au suivant que Observablelorsque le précédent est terminé. Utilisez-le lorsque l'ordre est important et que vous souhaitez conserver les ressources. Un exemple parfait est de reporter un appel réseau en vérifiant d'abord le cache. Cela peut généralement être suivi d'un .first()ou .takeFirst()pour éviter de faire un travail inutile.

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

  • concatMapEagerfonctionne à peu près de la même manière mais s'abonne à autant que possible (dépend de la plate-forme) mais n'émettra qu'une fois le précédent Observableterminé. Parfait lorsque vous avez beaucoup de traitement parallèle à faire, mais (contrairement à flatMap) vous souhaitez conserver l'ordre d'origine.

  • switchMaps'abonnera aux dernières Observablerencontres et se désabonnera de tous les précédents Observable. C'est parfait pour des cas tels que les suggestions de recherche: une fois qu'un utilisateur a changé sa requête de recherche, l'ancienne requête n'a plus aucun intérêt, elle est donc désabonnée et un point de terminaison Api bien comporté annulera la requête réseau.

Si vous retournez des Observables qui ne font pas partie d' subscribeOnun 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. Ensuite, vous pouvez obtenir de nombreux avantages du traitement parallèle et en vous désabonnant ou en ne vous abonnant pas intelligemment des Observables qui n'intéressent pas vos Subscribers

  • ambpeut également présenter un intérêt. Étant donné un nombre quelconque de Observables, il émet les mêmes éléments que le premier Observableà é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, le tri, vous pouvez effectuer ambun tri rapide avec un tri par fusion et utiliser celui qui est le plus rapide.
Andrew Gallasch
la source
1
If you are returning Observables that don't subscribeOn another thread, all of the above methods may behave much the same.- chaque explication que switchMap vs flatMapj'ai rencontrée auparavant, j'ai raté cet aspect important, maintenant tout est plus clair. Je vous remercie.
Andy Res
55

switchMap s'appelait autrefois flatMapLatest dans RxJS 4.

Il transmet simplement les événements du dernier Observable et se désabonne du précédent.

Sentenza
la source
@EpicPandaForce Bien qu'il soit incompatible avec combineLatest, qui émet les dernières valeurs chaque fois qu'une observable source émet (pas une seule fois).
Michael Fry
2
La raison pour laquelle il est appelé switchMap est que vous pouvez implémenter cet opérateur vous-même en utilisant o.map (...). Switch (). Bien qu'alors, j'imagine que ce serait mapSwitch, qui ne semble pas rouler si facilement.
Niall Connaughton
7

Map, FlatMap, ConcatMap et SwitchMap applique une fonction ou modifie les données émises par un observable.

  • Map modifie chaque élément émis par une source Observable et émet l'élément modifié.

  • FlatMap, SwitchMap et ConcatMap appliquent également une fonction sur chaque élément émis mais au lieu de renvoyer l'élément modifié, il renvoie l'Observable lui-même qui peut à nouveau émettre des données.

  • Le travail de FlatMap et de ConcatMap est à peu près le même. Ils fusionnent les éléments émis par plusieurs observables et retournent un seul observable.

  • La différence entre FlatMap et ConcatMap est l'ordre dans lequel les éléments sont émis.
  • FlatMap peut entrelacer des éléments lors de l'émission, c'est-à-dire que l'ordre des éléments émis n'est pas maintenu.
  • ConcatMap préserve l'ordre des éléments. Mais le principal inconvénient de ConcatMap est qu'il doit attendre que chaque observable termine son travail, donc asynchrone n'est pas maintenu.
  • SwitchMap est un peu différent de FlatMap et ConcatMap . SwitchMap se désabonne de la source précédente Observable chaque fois qu'un nouvel élément a commencé à émettre, émettant ainsi toujours les éléments de l'Observable actuel.
akhilesh0707
la source
1

Si vous recherchez 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

Paul
la source
4
Mais vous manquez la caractéristique clé de switchMap qui le distingue de flatMap - seuls les plus récents observables comptent, tout en vous désabonnant des précédents.
Artem Novikov
3
Dans cet exemple, lorsque vous remplacez switchMappar, flatMapcela fonctionnera exactement de la même manière.
Piotr Wittchen
1

Voici une plus - 101 longue ligne par exemple . Cela explique la chose pour moi.

Comme on l'a dit: il obtient le dernier observable (le plus lent 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é.

ses
la source