Apa perbedaan antara flatmap dan switchmap di RxJava?

149

The rxjava doc definisi switchmap agak kabur dan link ke halaman yang sama seperti flatMap. Apa perbedaan antara kedua operator?

Julian Go
sumber
1
Tentang itu tautan ke halaman yang sama dengan flatmap . Itu benar. Tetapi gulir ke bawah ke bagian Informasi Khusus Bahasa dan buka operator yang menarik. Saya pikir ini harus dilakukan secara otomatis dari TOC, tapi ... Anda juga dapat melihat gambar yang sama di javadoc .
Ruslan Stelmachenko

Jawaban:

180

Menurut dokumentasi ( http://reactivex.io/documentation/operators/flatmap.html )

yang switchMapadalah seperti flatMap, tapi itu hanya akan memancarkan item dari diamati baru sampai acara baru yang dipancarkan dari sumber yang dapat diamati.

Diagram marmer menunjukkannya dengan baik. Perhatikan perbedaan dalam diagram:

Dalam emisi asliswitchMap kedua ( marmer hijau ) tidak memancarkan emisi yang dipetakan kedua ( kotak hijau ), karena emisi asli ketiga ( marmer biru ) telah dimulai dan sudah memancarkan emisi yang dipetakan pertama ( berlian biru ). Dengan kata lain, hanya yang pertama dari dua dipetakan emisi hijau terjadi; tidak ada kotak hijau yang dipancarkan karena berlian biru mengalahkannya.

Di flatMap, semua hasil yang dipetakan akan dipancarkan, bahkan jika itu "basi". Dengan kata lain, baik emisi hijau pertama dan kedua yang dipetakan terjadi - kotak hijau akan dipancarkan (jika mereka menggunakan fungsi peta yang konsisten; karena tidak, Anda melihat berlian hijau kedua , meskipun dipancarkan setelah yang pertama berlian biru)

switchMap di switchMap jika yang asli dapat diamati mengeluarkan sesuatu yang baru, emisi sebelumnya tidak lagi menghasilkan yang dapat dipetakan yang dapat dipetakan;  ini adalah cara yang efektif untuk menghindari hasil basi

flatMap

di switchMap jika yang asli dapat diamati mengeluarkan sesuatu yang baru, emisi sebelumnya tidak lagi menghasilkan yang dapat dipetakan yang dapat dipetakan;  ini adalah cara yang efektif untuk menghindari hasil yang basi

dwursteisen
sumber
4
Terima kasih, diagram ini sangat membantu. Apakah Anda tahu contoh dunia nyata di mana switchMap akan digunakan?
Julian Go
1
@JulianGo ada contoh di sini: github.com/samuelgruetter/rx-playground/blob/master/… Menggunakan .map(func).switch, tapi itu sama dengan .switchMap(func).
Samuel Gruetter
2
Untuk berjaga-jaga jika seseorang masih membutuhkan contoh dunia nyata dari switchMap, ia dapat mengikuti tautan tautan ini dan akan mengerti kapan harus menggunakan swicthMap alih-alih flatMap.
hermannovich
2
Sebagai contoh menggunakan SwitchMap dari Ben Lesh menggunakan RxJs5 - lihat menit 25-26 di sini - youtube.com/watch?v=3LKMwkuK0ZE untuk saya, flatmap sudah dipahami ...
arcseldon
7
Diagram marmer menunjukkannya dengan baik? Apa? Saya kira jika Anda sudah mengerti switchmap mungkin.
Helzgate
166

Saya menemukan ini ketika menerapkan "pencarian instan" - yaitu ketika pengguna mengetik dalam kotak teks, dan hasilnya muncul dalam waktu dekat dengan setiap stroke tombol. Solusinya tampaknya:

  1. Punya subjek, seperti PublishSubject of String
  2. Di kotak teks ubah panggilan balik, aktifkan .onNext (teks)
  3. terapkan filter .debounce untuk menilai batas permintaan server
  4. terapkan .switchMap untuk melakukan kueri server - mengambil istilah pencarian dan mengembalikan yang bisa ditelusuri dari SearchResponse
  5. terapkan .subscribe dengan metode yang menggunakan SearchResponse dan memperbarui UI.

Dengan flatMap, hasil pencarian bisa basi, karena respons pencarian mungkin kembali rusak. Untuk memperbaikinya, switchMap harus digunakan, karena memastikan bahwa yang lama dapat diobservasi dibatalkan berlangganan begitu yang lebih baru disediakan.

Jadi, dalam ringkasan, flatMap harus digunakan ketika semua hasil penting, terlepas dari waktu mereka, dan switchMap harus digunakan ketika hanya hasil dari masalah yang dapat diamati terakhir.

pengguna4698855
sumber
Anda dapat memeriksa contoh ini di GitHub
Cabezas
95

Tidak ada diskusi flatMap yang lengkap tanpa membandingkan dan kontras dengan switchMap, concatMapdan concatMapEager.

Semua metode ini mengambil a Func1yang mengubah aliran menjadi Observables yang kemudian dipancarkan; perbedaannya adalah ketika yang dikembalikan Observableitu berlangganan dan berhenti berlangganan, dan jika dan ketika emisi mereka Observabledikeluarkan oleh ____Mapoperator yang bersangkutan.

  • flatMapberlangganan sebanyak mungkin yang dipancarkan Observable. (Ini adalah nomor yang bergantung pada platform. Mis. Angka yang lebih rendah pada Android) Gunakan ini ketika pesanan TIDAK penting, dan Anda ingin emisi SECEPATNYA.
  • concatMapberlangganan yang pertama Observabledan hanya berlangganan berikutnya Observableketika yang sebelumnya telah selesai. Gunakan ini ketika pesanan penting dan Anda ingin menghemat sumber daya. Contoh yang sempurna adalah menunda panggilan jaringan dengan memeriksa cache terlebih dahulu. Itu biasanya dapat diikuti oleh .first()atau .takeFirst()untuk menghindari melakukan pekerjaan yang tidak perlu.

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

  • concatMapEagerbekerja hampir sama tetapi berlangganan sebanyak mungkin (tergantung platform) tetapi hanya akan memancarkan setelah sebelumnya Observabletelah selesai. Sempurna ketika Anda memiliki banyak pemrosesan paralel yang perlu dilakukan, tetapi (tidak seperti flatMap) Anda ingin mempertahankan pesanan asli.

  • switchMapakan berlangganan ke pertemuan terakhir Observabledan berhenti berlangganan dari semua sebelumnya Observable. Ini sempurna untuk kasus-kasus seperti saran pencarian: setelah pengguna mengubah permintaan pencarian mereka, permintaan lama tidak lagi menarik, jadi itu berhenti berlangganan, dan titik akhir Api yang berperilaku baik akan membatalkan permintaan jaringan.

Jika Anda mengembalikan Observableyang tidak subscribeOnmenggunakan utas lain, semua metode di atas mungkin berperilaku sama. Perilaku menarik, dan berguna muncul ketika Anda mengizinkan sarang Observableuntuk bertindak di utas mereka sendiri. Maka Anda bisa mendapatkan banyak manfaat dari pemrosesan paralel, dan dengan cerdas berhenti berlangganan atau tidak berlangganan dari Observableyang tidak menarik minat Anda Subscriber.

  • ambmungkin juga menarik. Mengingat sejumlah Observables itu memancarkan item yang sama bahwa orang pertama yang Observablememancarkan apa pun memancarkan. Itu bisa berguna ketika Anda memiliki banyak sumber yang dapat / harus mengembalikan hal yang sama dan Anda menginginkan kinerja. misalnya penyortiran, Anda mungkin menyortir ambcepat dengan penggabungan-penggabungan dan menggunakan mana yang lebih cepat.
Andrew Gallasch
sumber
1
If you are returning Observables that don't subscribeOn another thread, all of the above methods may behave much the same.- setiap penjelasan yang switchMap vs flatMapsaya temui sebelumnya, melewatkan aspek penting ini, sekarang semuanya lebih jelas. Terima kasih.
Andy Res
55

switchMap dulunya disebut flatMapLatest di RxJS 4.

Ini pada dasarnya hanya meneruskan acara dari Observable terbaru dan berhenti berlangganan dari yang sebelumnya.

Sentenza
sumber
@EpicPandaForce Meskipun tidak konsisten dengan CombatLatest, yang memancarkan nilai terbaru setiap kali sumber memancarkan emisi (tidak memancarkan sekali).
Michael Fry
2
Sebagian alasannya disebut switchMap adalah karena Anda dapat mengimplementasikan operator ini sendiri dengan menggunakan o.map (...). Switch (). Meskipun begitu aku akan membayangkan itu akan menjadi mapSwitch, yang sepertinya tidak menggulung lidah dengan mudah.
Niall Connaughton
7

Peta, FlatMap, ConcatMap dan SwitchMap menerapkan fungsi atau memodifikasi data yang dipancarkan oleh Observable.

  • Peta memodifikasi setiap item yang dipancarkan oleh sumber. Dapat diobservasi dan memancarkan item yang dimodifikasi.

  • FlatMap, SwitchMap, dan ConcatMap juga menerapkan fungsi pada setiap item yang dipancarkan tetapi alih-alih mengembalikan item yang dimodifikasi, ia mengembalikan Observable sendiri yang dapat memancarkan data lagi.

  • Pekerjaan FlatMap dan ConcatMap hampir sama. Mereka menggabungkan item yang dipancarkan oleh beberapa Observable dan mengembalikan satu Observable tunggal.

  • Perbedaan antara FlatMap dan ConcatMap adalah urutan item dipancarkan.
  • FlatMap dapat melakukan interleave item saat memancarkan yaitu pesanan item yang dipancarkan tidak dipertahankan.
  • ConcatMap mempertahankan urutan item. Tetapi kerugian utama dari ConcatMap adalah, ia harus menunggu setiap Observable menyelesaikan pekerjaannya sehingga asinkron tidak dipertahankan.
  • SwitchMap sedikit berbeda dari FlatMap dan ConcatMap . SwitchMap berhenti berlangganan dari sumber sebelumnya yang dapat diobservasi setiap kali item baru mulai dipancarkan, sehingga selalu memancarkan item dari Observable saat ini.
akhilesh0707
sumber
1

Jika Anda mencari kode contoh

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

}

Anda dapat melihat lebih banyak contoh di sini https://github.com/politrons/reactive

paul
sumber
4
Tetapi Anda kehilangan fitur utama switchMap yang membedakannya dari flatMap - hanya hal-hal yang dapat diobservasi terbaru, sementara berhenti berlangganan dari yang sebelumnya.
Artem Novikov
3
Dalam contoh ini, ketika Anda mengganti switchMapdengan flatMapitu akan bekerja sama persis.
Piotr Wittchen
1

Ini adalah satu lagi - contoh panjang 101 baris . Itu menjelaskan hal bagi saya.

Seperti yang dikatakan: itu mendapat yang terakhir diamati (yang paling lambat jika Anda mau) dan mengabaikan sisanya.

Hasil dari:

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

Anda melihat nilai A diabaikan.

ses
sumber