Qual è la differenza tra flatmap e switchmap in RxJava?


149

Il documento rxjava definizione del di switchmap è piuttosto vaga e si collega alla stessa pagina di flatmap. Qual è la differenza tra i due operatori?


1
Su di esso si collega alla stessa pagina di flatmap . È veramente vero Scorri verso il basso fino alla sezione Informazioni specifiche sulla lingua e apri un operatore interessante. Penso che questo dovrebbe essere fatto automaticamente da TOC, ma ... Inoltre puoi vedere la stessa immagine in javadoc .
Ruslan Stelmachenko,

Risposte:


180

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

il switchMapè come il flatMap, ma sarà solo emettere elementi dalla nuova osservabile fino a quando un nuovo evento viene emesso dalla osservabile fonte.

Lo schema in marmo lo mostra bene. Notare la differenza nei diagrammi:

Nella switchMapseconda emissione originale ( marmo verde ) non emette la sua seconda emissione mappata ( quadrato verde ), poiché la terza emissione originale ( marmo blu ) è iniziata e ha già emesso la sua prima emissione mappata ( diamante blu ). In altre parole, si verifica solo la prima delle due emissioni verdi mappate ; non viene emesso alcun quadrato verde perché il diamante blu lo ha battuto.

In flatMap, tutti i risultati mappati verranno emessi, anche se "stantio". In altre parole, si verificano sia la prima che la seconda delle emissioni verdi mappate : sarebbe stato emesso un quadrato verde (se avessero usato una funzione cartografica coerente; poiché non lo facevano, si vede il secondo diamante verde, anche se viene emesso dopo il primo diamante blu)

switchMap in switchMap se l'originale osservabile emette qualcosa di nuovo, le emissioni precedenti non producono più osservabili mappati;  questo è un modo efficace per evitare risultati non aggiornati

flatMap

in switchMap se l'originale osservabile emette qualcosa di nuovo, le emissioni precedenti non producono più osservabili mappati;  questo è un modo efficace per ottenere risultati non aggiornati


4
Grazie, il diagramma è molto utile. Conosci un esempio del mondo reale in cui sarebbe utilizzato switchMap?
Julian Go,

1
@JulianVai un esempio qui: github.com/samuelgruetter/rx-playground/blob/master/… Utilizza .map(func).switch, ma è lo stesso .switchMap(func).
Samuel Gruetter,

2
Nel caso in cui qualcuno abbia ancora bisogno di un esempio reale di switchMap, può seguire questo link di link e capirà quando usare swicthMap invece di flatMap.
hermannovich,

2
Per un esempio usando SwitchMap di Ben Lesh usando RxJs5 - vedi i minuti 25-26 qui - youtube.com/watch?v=3LKMwkuK0ZE per me, la mappa piatta era già compresa ...
arcseldon

7
Lo schema in marmo lo mostra bene? Che cosa? Immagino che forse hai già capito switchmap.
Helzgate

166

Mi sono imbattuto in questo quando ho implementato la "ricerca istantanea", ovvero quando l'utente digita in una casella di testo e i risultati appaiono quasi in tempo reale ad ogni pressione del tasto. La soluzione sembra essere:

  1. Avere un argomento, ad esempio PublishSubject of String
  2. Nella casella di testo cambia callback, invoca .onNext (testo)
  3. applica il filtro .debounce alle query del server con limite di velocità
  4. applica .switchMap per eseguire una query del server - prendendo il termine di ricerca e restituendo Observable di SearchResponse
  5. applicare .subscribe con un metodo che utilizza SearchResponse e aggiorna l'interfaccia utente.

Con flatMap, i risultati della ricerca potrebbero essere obsoleti, poiché le risposte alla ricerca potrebbero non funzionare più. Per risolvere questo problema, è necessario utilizzare switchMap, poiché garantisce che un vecchio osservabile venga annullato una volta fornito uno nuovo.

Quindi, in sintesi, flatMap dovrebbe essere usato quando tutti i risultati contano, indipendentemente dalla loro tempistica, e switchMap dovrebbe essere usato quando solo i risultati dell'ultima materia osservabile.


Puoi controllare questo esempio in GitHub
Cabezas

95

Nessuna discussione flatMap è completa senza confrontare e contrastare con switchMap, concatMape concatMapEager.

Tutti questi metodi prendono un Func1che trasforma il flusso in Observables che vengono quindi emessi; la differenza è quando gli Observables restituiti sono sottoscritti e non iscritti e se e quando tali emissioni Observablesono emesse ____Mapdall'operatore in questione.

  • flatMapsottoscrive il maggior numero possibile di messaggi emessi Observable. (È un numero dipendente dalla piattaforma. Ad es. Un numero inferiore su Android) Utilizzalo quando l'ordine NON è importante e vuoi le emissioni al più presto.
  • concatMapsi iscrive al primo Observablee si abbona al successivo solo Observablequando il precedente è stato completato. Usalo quando l'ordine è importante e vuoi conservare le risorse. Un esempio perfetto è il rinvio di una chiamata di rete controllando prima la cache. Ciò può essere in genere seguito da un .first()o .takeFirst()per evitare di fare un lavoro non necessario.

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

  • concatMapEagerfunziona allo stesso modo ma si abbona al maggior numero possibile (dipende dalla piattaforma) ma emetterà solo una volta Observablecompletato il precedente . Perfetto quando hai molte elaborazioni parallele che devono essere fatte, ma (a differenza di flatMap) vuoi mantenere l'ordine originale.

  • switchMapsi iscriverà all'ultimo Observableincontro e annullerà l' iscrizione a tutti i precedenti Observable. Questo è perfetto per casi come i suggerimenti di ricerca: una volta che un utente ha modificato la propria query di ricerca, la vecchia richiesta non ha più alcun interesse, quindi viene annullata l'iscrizione e un end-point Api ben educato annullerà la richiesta di rete.

Se stai restituendo messaggi Observableche non hanno subscribeOnun altro thread, tutti i metodi sopra descritti potrebbero comportarsi in modo simile. Il comportamento interessante e utile emerge quando si consente agli Observables nidificati di agire sui propri thread. Poi si può ottenere ottenere un sacco di benefici da elaborazione parallela, e intelligentemente cancellarsi o meno la sottoscrizione da Observables che non interessano i vostri Subscribers

  • ambpotrebbe anche essere di interesse. Dato un numero qualsiasi di Observables, emette gli stessi elementi emessi dal primo Observablead emettere qualcosa. Ciò potrebbe essere utile quando hai più fonti che potrebbero / dovrebbero restituire la stessa cosa e desideri prestazioni. ad esempio l'ordinamento, è possibile ambeseguire l'ordinamento rapido con un tipo di unione e utilizzare quello più veloce.

1
If you are returning Observables that don't subscribeOn another thread, all of the above methods may behave much the same.- ogni spiegazione che switchMap vs flatMapho incontrato prima mi mancava questo aspetto importante, ora tutto è più chiaro. Grazie.
Andy Res

55

switchMap una volta era chiamato flatMapLatest in RxJS 4.

Fondamentalmente trasmette solo gli eventi dell'ultimo osservabile e annulla l'iscrizione al precedente.


@EpicPandaForce Sebbene sia incompatibile con CombinaLatest, che emette i valori più recenti ogni volta che viene emessa una fonte osservabile (non una volta).
Michael Fry,

2
In parte il motivo per cui si chiama switchMap è perché puoi implementare questo operatore da solo usando o.map (...). Switch (). Anche se poi immaginerei che sarebbe mapSwitch, che non sembra rotolare fuori dalla lingua così facilmente.
Niall Connaughton,

7

Map, FlatMap, ConcatMap e SwitchMap applicano una funzione o modificano i dati emessi da un osservabile.

  • Mappa modifica ogni elemento emesso da un osservabile di origine ed emette l'elemento modificato.

  • FlatMap, SwitchMap e ConcatMap applicano anche una funzione su ogni elemento emesso ma invece di restituire l'elemento modificato, restituisce l'Osservabile stesso che può emettere nuovamente dati.

  • Il lavoro di FlatMap e ConcatMap è praticamente lo stesso. Uniscono gli elementi emessi da più osservabili e restituiscono un singolo osservabile.

  • La differenza tra FlatMap e ConcatMap è l'ordine in cui gli articoli vengono emessi.
  • FlatMap può intercalare gli articoli durante l'emissione, ovvero l'ordine degli articoli emessi non viene mantenuto.
  • ConcatMap conserva l'ordine degli articoli. Ma il principale svantaggio di ConcatMap è che deve attendere che ogni osservabile completi il ​​proprio lavoro, quindi non viene mantenuta la sincronizzazione asincrona.
  • SwitchMap è leggermente diverso da FlatMap e ConcatMap . SwitchMap annulla l' iscrizione alla fonte precedente Osservabile ogni volta che iniziava a emettere un nuovo oggetto, emettendo sempre gli oggetti dall'osservabile corrente.

1

Se stai cercando un codice di esempio

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

}

Puoi vedere altri esempi qui https://github.com/politrons/reactive


4
Ma ti manca la caratteristica chiave di switchMap che la distingue da flatMap - solo le più recenti questioni osservabili, mentre si annulla l'iscrizione a quelle precedenti.
Artem Novikov,

3
In questo esempio, quando si sostituisce switchMapcon flatMapfunzionerà esattamente la stessa cosa.
Piotr Wittchen,

1

Ecco un altro esempio di 101 righe . Questo spiega la cosa per me.

Come è stato detto: ottiene l'ultimo osservabile (il più lento se vuoi) e ignora il resto.

Di conseguenza:

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

Vedi la A è stata ignorata.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.