Was ist der Unterschied zwischen Flatmap und Switchmap in RxJava?


149

Die rxjava-Dokumentdefinition von switchmap ist ziemlich vage und verweist auf dieselbe Seite wie flatmap. Was ist der Unterschied zwischen den beiden Operatoren?


1
Über es Links zu der gleichen Seite wie flatmap . Es ist wirklich wahr. Scrollen Sie jedoch nach unten zum Abschnitt Sprachspezifische Informationen und öffnen Sie den interessanten Operator. Ich denke, dies sollte automatisch vom Inhaltsverzeichnis aus erfolgen, aber ... Sie können das gleiche Bild auch in Javadoc sehen .
Ruslan Stelmachenko

Antworten:


180

Laut Dokumentation ( http://reactivex.io/documentation/operators/flatmap.html )

Das switchMapist wie das flatMap, aber es werden nur Elemente von der neuen Observable ausgegeben, bis ein neues Ereignis von der Source Observable ausgegeben wird.

Das Marmordiagramm zeigt es gut. Beachten Sie den Unterschied in den Diagrammen:

Bei switchMapder zweiten ursprünglichen Emission ( grüner Marmor ) wird die zweite abgebildete Emission ( grünes Quadrat ) nicht emittiert , da die dritte ursprüngliche Emission ( blauer Marmor ) begonnen hat und bereits die erste abgebildete Emission ( blauer Diamant ) emittiert . Mit anderen Worten, nur die erste von zwei kartierten grünen Emissionen tritt auf; Es wird kein grünes Quadrat ausgegeben, weil der blaue Diamant es geschlagen hat.

In flatMapwerden alle zugeordneten Ergebnisse ausgegeben, auch wenn sie "veraltet" sind. Mit anderen Worten, sowohl ersten und zweiter der abgebildeten passieren grün - Emissionen - ein grünes Quadrat emittiert habe würde (wenn sie konsistent Map - Funktion verwendet, da sie nicht, haben Sie den sehen zweiten grünen Diamanten, auch wenn es ausgestrahlt wird nach der erste blaue Diamant)

switchMap Wenn in switchMap das ursprüngliche Observable etwas Neues emittiert, erzeugen frühere Emissionen keine abgebildeten Observables mehr.  Dies ist ein effektiver Weg, um veraltete Ergebnisse zu vermeiden

flatMap

Wenn in switchMap das ursprüngliche Observable etwas Neues emittiert, erzeugen frühere Emissionen keine abgebildeten Observables mehr.  Dies ist ein effektiver Weg, um veraltete Ergebnisse zu vermeiden


4
Danke, das Diagramm ist sehr hilfreich. Kennen Sie ein Beispiel aus der Praxis, in dem switchMap verwendet wird?
Julian Go

1
@JulianGo hier gibt es ein Beispiel: github.com/samuelgruetter/rx-playground/blob/master/… Es wird verwendet .map(func).switch, aber das ist das gleiche wie .switchMap(func).
Samuel Gruetter

2
Nur für den Fall jemand noch eine reale Welt Beispiel für switchMap benötigen, kann er diesen Link folgen Link und sie werden verstehen , wenn swicthMap statt flatMap zu verwenden.
Hermannovich

2
Ein Beispiel für die Verwendung von SwitchMap von Ben Lesh mit RxJs5 - siehe Minuten 25-26 hier - youtube.com/watch?v=3LKMwkuK0ZE für mich, Flatmap wurde bereits verstanden ...
arcseldon

7
Das Marmordiagramm zeigt es gut? Was? Ich denke, wenn Sie Switchmap vielleicht schon verstehen.
Helzgate

166

Dies ist mir bei der Implementierung der "Sofort-Suche" begegnet, dh wenn der Benutzer ein Textfeld eingibt und die Ergebnisse bei jedem Tastendruck nahezu in Echtzeit angezeigt werden. Die Lösung scheint zu sein:

  1. Haben Sie einen Betreff, z. B. PublishSubject of String
  2. Rufen Sie im Textfeld Rückruf ändern .onNext (Text) auf.
  3. Wenden Sie den .debounce-Filter an, um Serverabfragen mit Ratenbegrenzung durchzuführen
  4. Wenden Sie .switchMap an, um eine Serverabfrage durchzuführen. Nehmen Sie den Suchbegriff und geben Sie Observable of SearchResponse zurück
  5. Wenden Sie .subscribe mit einer Methode an, die SearchResponse verwendet und die Benutzeroberfläche aktualisiert.

Mit flatMap können die Suchergebnisse veraltet sein, da die Suchantworten möglicherweise nicht mehr in der richtigen Reihenfolge angezeigt werden. Um dies zu beheben, sollte switchMap verwendet werden, da dadurch sichergestellt wird, dass ein altes Observable abgemeldet wird, sobald ein neueres bereitgestellt wird.

Zusammenfassend sollte flatMap verwendet werden, wenn alle Ergebnisse unabhängig von ihrem Zeitpunkt von Bedeutung sind, und switchMap sollte verwendet werden, wenn nur Ergebnisse aus der letzten beobachtbaren Angelegenheit von Bedeutung sind.



95

Kein flatMap Diskussion ist ohne Vergleich und Kontrast mit switchMap, concatMapund concatMapEager.

Alle diese Methoden nehmen eine Func1, die den Strom in Observables umwandelt, die dann ausgegeben werden; Der Unterschied besteht darin, wann die zurückgegebenen Observables gezeichnet und nicht abonniert werden und ob und wann diese die Emissionen dieser Observables vom ____Mapbetreffenden Betreiber emittiert werden .

  • flatMapabonniert so viele emittierte Observables wie möglich. (Dies ist eine plattformabhängige Nummer, z. B. eine niedrigere Nummer unter Android.) Verwenden Sie diese Option, wenn die Reihenfolge NICHT wichtig ist und Sie so schnell wie möglich Emissionen wünschen.
  • concatMapAbonniert den ersten Observableund erst den nächsten, Observablewenn der vorherige abgeschlossen ist. Verwenden Sie diese Option, wenn die Reihenfolge wichtig ist und Sie Ressourcen schonen möchten. Ein perfektes Beispiel ist das Verschieben eines Netzwerkaufrufs, indem zuerst der Cache überprüft wird. Darauf kann in der Regel ein .first()oder folgen .takeFirst(), um unnötige Arbeiten zu vermeiden.

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

  • concatMapEagerfunktioniert ähnlich, abonniert jedoch so viele wie möglich (plattformabhängig), wird jedoch erst ausgegeben, wenn der vorherige ObservableVorgang abgeschlossen ist. Perfekt, wenn Sie viel Parallelverarbeitung durchführen müssen, aber (im Gegensatz zu flatMap) die ursprüngliche Reihenfolge beibehalten möchten.

  • switchMapwird das letzte abonnieren, auf das Observablees trifft, und sich von allen vorherigen abmelden Observable. Dies ist perfekt für Fälle wie Suchvorschläge: Sobald ein Benutzer seine Suchanfrage geändert hat, ist die alte Anfrage nicht mehr von Interesse, daher wird sie abgemeldet, und ein gut erzogener Api-Endpunkt bricht die Netzwerkanfrage ab.

Wenn Sie Observables zurückgeben, die keinen subscribeOnanderen Thread haben, verhalten sich alle oben genannten Methoden möglicherweise ähnlich. Das interessante und nützliche Verhalten tritt auf, wenn Sie den verschachtelten Observables erlauben , auf ihre eigenen Threads zu reagieren. Dann können Sie viele Vorteile aus der parallelen Verarbeitung ziehen und sich intelligent von Observables abmelden oder nicht abonnieren , die Ihre Subscribers nicht interessieren

  • ambkann auch von Interesse sein. Bei einer beliebigen Anzahl von Observables werden dieselben Elemente ausgegeben, die der erste Observable, der etwas ausgibt, ausgibt. Dies kann nützlich sein, wenn Sie mehrere Quellen haben, die dasselbe zurückgeben könnten / sollten und Leistung wünschen. Beispiel: Sortieren, Sie können ambeine schnelle Sortierung mit einer Zusammenführungssortierung durchführen und die schnellere verwenden.

1
If you are returning Observables that don't subscribeOn another thread, all of the above methods may behave much the same.- Jede Erklärung, die switchMap vs flatMapmir zuvor begegnet ist, hat diesen wichtigen Aspekt übersehen, jetzt ist alles klarer. Danke dir.
Andy Res

55

switchMap wurde einmal flatMapLatest genannt in RxJS 4 .

Grundsätzlich werden nur die Ereignisse aus dem neuesten Observable weitergegeben und das vorherige abgemeldet.


@EpicPandaForce Obwohl es nicht mit combinLatest übereinstimmt, das die neuesten Werte ausgibt, wenn eine beobachtbare Quelle ausgibt (nicht einmal ausgibt).
Michael Fry

2
Der Grund für den Namen switchMap liegt zum Teil darin, dass Sie diesen Operator mithilfe von o.map (...). Switch () selbst implementieren können. Dann würde ich mir allerdings vorstellen, dass es sich um mapSwitch handelt, der nicht so leicht von der Zunge zu rollen scheint.
Niall Connaughton

7

Map, FlatMap, ConcatMap und SwitchMap wenden eine Funktion an oder ändern die von einem Observable ausgegebenen Daten.

  • Map ändert jedes von einer beobachtbaren Quelle ausgegebene Element und gibt das geänderte Element aus.

  • FlatMap, SwitchMap und ConcatMap wenden ebenfalls eine Funktion auf jedes ausgegebene Element an. Anstatt das geänderte Element zurückzugeben, wird das Observable selbst zurückgegeben, das erneut Daten ausgeben kann.

  • FlatMap- und ConcatMap- Arbeit ist ziemlich gleich. Sie führen Elemente zusammen, die von mehreren Observables ausgegeben wurden, und geben eine einzelne Observable zurück.

  • Der Unterschied zwischen FlatMap und ConcatMap besteht in der Reihenfolge, in der die Artikel ausgegeben werden.
  • FlatMap kann Elemente während der Ausgabe verschachteln, dh die Reihenfolge der ausgegebenen Elemente wird nicht beibehalten.
  • ConcatMap behält die Reihenfolge der Elemente bei. Der Hauptnachteil von ConcatMap ist jedoch, dass es warten muss, bis jedes Observable seine Arbeit abgeschlossen hat, sodass die asynchrone Funktion nicht beibehalten wird.
  • SwitchMap unterscheidet sich ein wenig von FlatMap und ConcatMap . SwitchMap meldet sich von der vorherigen Quelle Observable ab, wenn ein neues Element ausgegeben wird, und sendet daher immer die Elemente von der aktuellen Observable.

1

Wenn Sie nach einem Beispielcode suchen

/**
 * 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);

}

Weitere Beispiele finden Sie hier https://github.com/politrons/reactive


4
Sie vermissen jedoch die Hauptfunktion von switchMap, die es von flatMap unterscheidet - nur die neuesten Observable-Themen, während Sie sich von den vorherigen abmelden.
Artem Novikov

3
In diesem Beispiel , wenn Sie ersetzen switchMapmit flatMapwird es funktioniert genau gleich.
Piotr Wittchen

1

Hier ist das eine weitere - 101 Zeilen lange Beispiel . Das erklärt die Sache für mich.

Wie gesagt: Es wird das letzte beobachtbare (das langsamste, wenn Sie so wollen) und ignoriert den Rest.

Als Ergebnis:

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

Sie sehen, das A wurde ignoriert.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.