Kapan Anda menggunakan map
vs flatMap
di RxJava ?
Katakanlah, misalnya, kami ingin memetakan File yang berisi JSON ke dalam Strings yang berisi JSON--
Menggunakan map
, kita harus berurusan dengan Exception
entah bagaimana. Tapi bagaimana caranya?:
Observable.from(jsonFile).map(new Func1<File, String>() {
@Override public String call(File file) {
try {
return new Gson().toJson(new FileReader(file), Object.class);
} catch (FileNotFoundException e) {
// So Exception. What to do ?
}
return null; // Not good :(
}
});
Menggunakan flatMap
, ini jauh lebih bertele-tele, tetapi kita bisa meneruskan masalah ke bawah rantai Observables
dan menangani kesalahan jika kita memilih tempat lain dan bahkan coba lagi:
Observable.from(jsonFile).flatMap(new Func1<File, Observable<String>>() {
@Override public Observable<String> call(final File file) {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override public void call(Subscriber<? super String> subscriber) {
try {
String json = new Gson().toJson(new FileReader(file), Object.class);
subscriber.onNext(json);
subscriber.onCompleted();
} catch (FileNotFoundException e) {
subscriber.onError(e);
}
}
});
}
});
Saya suka kesederhanaan map
, tetapi penanganan kesalahan flatmap
(bukan verbositas). Saya belum melihat praktik terbaik tentang hal ini dan saya ingin tahu bagaimana ini digunakan dalam praktik.
subscriber.onError()
dll. Semua contoh yang saya lihat memiliki kesalahan yang dialihkan seperti itu. Apakah itu tidak masalah?OnErrorThrowable
areprivate
dan Anda perlu menggunakanOnErrorThrowable.from(e)
sebagai gantinya.FlatMap berperilaku sangat mirip dengan peta, perbedaannya adalah bahwa fungsi yang diterapkannya mengembalikan suatu yang dapat diamati sendiri, sehingga sangat cocok untuk memetakan pada operasi yang tidak sinkron.
Dalam arti praktis, fungsi Peta berlaku hanya membuat transformasi atas respon dirantai (tidak mengembalikan yang Teramati); sementara fungsi FlatMap berlaku mengembalikan sebuah
Observable<T>
, itu sebabnya FlatMap direkomendasikan jika Anda berencana untuk membuat panggilan tidak sinkron di dalam metode.Ringkasan:
Contoh yang jelas dapat dilihat di sini: http://blog.couchbase.com/why-couchbase-chose-rxjava-new-java-sdk .
Couchbase Java 2.X Client menggunakan Rx untuk menyediakan panggilan asinkron dengan cara yang nyaman. Karena menggunakan Rx, ia memiliki metode peta dan FlatMap, penjelasan dalam dokumentasi mereka mungkin membantu untuk memahami konsep umum.
Untuk menangani kesalahan, ganti onError pada susbcriber Anda.
Mungkin membantu untuk melihat dokumen ini: http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/
Sumber yang baik tentang cara mengelola kesalahan dengan RX dapat ditemukan di: https://gist.github.com/daschl/db9fcc9d2b932115b679
sumber
Dalam kasus Anda, Anda perlu peta, karena hanya ada 1 input dan 1 output.
Fungsi peta - yang disediakan hanya menerima item dan mengembalikan item yang akan dipancarkan lebih lanjut (hanya sekali) ke bawah.
flatMap - fungsi yang disediakan menerima item kemudian mengembalikan "Dapat Diobservasi", yang berarti setiap item dari "Dapat Diamati" baru akan dipancarkan secara terpisah lebih jauh ke bawah.
Mungkin kode akan menjelaskan semuanya untuk Anda:
Keluaran:
sumber
Cara saya berpikir tentang hal itu adalah bahwa Anda menggunakan
flatMap
ketika fungsi yang Anda ingin masukkanmap()
kembaliObservable
. Dalam hal ini Anda mungkin masih mencoba menggunakanmap()
tetapi itu tidak praktis. Biarkan saya mencoba menjelaskan mengapa.Jika dalam kasus seperti itu Anda memutuskan untuk tetap dengan
map
, Anda akan mendapatkanObservable<Observable<Something>>
. Misalnya dalam kasus Anda, jika kami menggunakan pustaka RxGson imajiner, yang mengembalikan metodeObservable<String>
dari itutoJson()
(bukan hanya mengembalikan aString
) itu akan terlihat seperti ini:Pada titik ini akan sangat sulit untuk
subscribe()
diamati. Di dalamnya Anda akan mendapatkanObservable<String>
yang Anda butuhkan lagisubscribe()
untuk mendapatkan nilai. Yang tidak praktis atau enak dilihat.Jadi untuk membuatnya berguna satu ide adalah untuk "meratakan" ini dapat diamati dari diamati (Anda mungkin mulai melihat dari mana nama _flat_Map berasal). RxJava menyediakan beberapa cara untuk meratakan yang dapat diamati dan demi kesederhanaan mari kita asumsikan penggabungan adalah apa yang kita inginkan. Penggabungan pada dasarnya mengambil banyak yang bisa diobservasi dan memancarkan setiap kali salah satu dari mereka memancarkan. (Banyak orang akan berpendapat bahwa beralih akan menjadi default yang lebih baik. Tetapi jika Anda hanya memancarkan satu nilai, itu tidak masalah.)
Jadi ubah cuplikan kami sebelumnya yang akan kami dapatkan:
Ini jauh lebih bermanfaat, karena dengan berlangganan (atau memetakan, atau memfilter, atau ...) Anda baru saja mendapatkan
String
nilainya. (Juga, ingatlah Anda, varian semacammerge()
itu tidak ada di RxJava, tetapi jika Anda memahami gagasan penggabungan maka saya harap Anda juga memahami cara kerjanya.)Jadi pada dasarnya karena itu
merge()
mungkin hanya akan berguna ketika berhasilmap()
mengembalikan yang dapat diamati dan jadi Anda tidak perlu mengetik ini berulang-ulang,flatMap()
diciptakan sebagai steno. Ini menerapkan fungsi pemetaan seperti biasamap()
, tetapi kemudian bukannya memancarkan nilai yang dikembalikan itu juga "meratakan" (atau menggabungkan) mereka.Itu kasus penggunaan umum. Ini sangat berguna dalam basis kode yang menggunakan Rx allover tempat dan Anda punya banyak metode mengembalikan yang dapat diamati, yang Anda ingin rantai dengan metode lain yang mengembalikan diamati.
Dalam use case Anda, itu kebetulan juga berguna, karena
map()
hanya dapat mengubah satu nilai yang dipancarkanonNext()
menjadi nilai lain yang dipancarkanonNext()
. Tapi itu tidak bisa mengubahnya menjadi beberapa nilai, tidak ada nilai sama sekali atau kesalahan. Dan seperti yang ditulis akarnokd dalam jawabannya (dan pikiran Anda dia jauh lebih pintar dari saya, mungkin secara umum, tetapi setidaknya ketika datang ke RxJava) Anda tidak harus membuang pengecualian dari Andamap()
. Jadi, alih-alih, Anda dapat menggunakanflatMap()
danketika semuanya berjalan dengan baik, tapi
ketika sesuatu gagal.
Lihat jawabannya untuk cuplikan lengkap: https://stackoverflow.com/a/30330772/1402641
sumber
Pertanyaannya adalah Kapan Anda menggunakan peta vs flatMap di RxJava? . Dan saya pikir demo sederhana lebih spesifik.
Saat Anda ingin mengonversi item yang dipancarkan ke jenis lain, dalam kasus Anda, mengonversi file ke String, map, dan flatMap dapat berfungsi. Tapi saya lebih suka operator peta karena lebih jelas.
Namun di beberapa tempat,
flatMap
bisa melakukan pekerjaan sihir tetapimap
tidak bisa. Sebagai contoh, saya ingin mendapatkan info pengguna tetapi saya harus mendapatkan idnya terlebih dahulu ketika pengguna masuk. Jelas saya membutuhkan dua permintaan dan semuanya dalam rangka.Mari kita mulai.
Berikut adalah dua metode, satu untuk masuk kembali
Response
, dan satu lagi untuk mengambil info pengguna.Seperti yang Anda lihat, dalam fungsi flatMap berlaku, pada awalnya saya mendapatkan id pengguna dari
Response
kemudian mengambil info pengguna. Ketika dua permintaan selesai, kita dapat melakukan pekerjaan kita seperti memperbarui UI atau menyimpan data ke dalam basis data.Namun jika Anda menggunakan
map
Anda tidak dapat menulis kode yang bagus. Singkatnya,flatMap
dapat membantu kami membuat serialisasi permintaan.sumber
Berikut ini adalah sederhana thumb-aturan yang saya gunakan membantu saya memutuskan seperti ketika menggunakan
flatMap()
lebihmap()
di RxObservable
.Setelah Anda mengambil keputusan bahwa Anda akan menggunakan
map
transformasi, Anda akan menulis kode transformasi Anda untuk mengembalikan beberapa Objek, kan?Jika yang Anda kembalikan sebagai hasil akhir dari transformasi Anda adalah:
objek yang tidak dapat diobservasi maka Anda hanya akan menggunakannya
map()
. Danmap()
membungkus objek itu dalam Observable dan memancarkannya.sebuah
Observable
objek, maka Anda akan gunakanflatMap()
. DanflatMap()
membuka bungkus yang dapat diobservasi, mengambil objek yang dikembalikan, membungkusnya dengan yang dapat diamati sendiri dan memancarkannya.Katakanlah misalnya kita memiliki metode titleCase (String inputParam) yang mengembalikan objek Titled Cased String dari param input. Jenis pengembalian metode ini bisa
String
atauObservable<String>
.Jika jenis pengembaliannya
titleCase(..)
hanya berupaString
, maka Anda akan menggunakannyamap(s -> titleCase(s))
Jika jenis pengembaliannya
titleCase(..)
adalahObservable<String>
, maka Anda akan menggunakanflatMap(s -> titleCase(s))
Harapan itu menjelaskan.
sumber
Saya hanya ingin menambahkan bahwa dengan
flatMap
, Anda tidak benar-benar perlu menggunakan kustom Anda sendiri yang dapat diamati di dalam fungsi dan Anda dapat mengandalkan metode / operator pabrik standar:Secara umum, Anda harus menghindari melempar (Runtime-) pengecualian dari metode onXXX dan callback jika memungkinkan, meskipun kami menempatkan perlindungan sebanyak mungkin di RxJava.
sumber
Dalam skenario yang menggunakan peta, Anda tidak perlu diamati untuk itu.
Anda harus menggunakan exception.propagate, yang merupakan pembungkus sehingga Anda dapat mengirim pengecualian yang diperiksa ke mekanisme rx
Anda kemudian harus menangani kesalahan ini di pelanggan
Ada posting yang sangat bagus untuk itu: http://blog.danlew.net/2015/12/12/error-handling-in-rxjava/
sumber
Dalam beberapa kasus Anda mungkin akhirnya memiliki rantai yang dapat diobservasi, di mana observable Anda akan mengembalikan observable lain. jenis 'flatmap' membuka bungkusan yang dapat diamati kedua yang terkubur di yang pertama dan membiarkan Anda langsung mengakses data yang diamati kedua diludahkan saat berlangganan.
sumber
Flatmap memetakan yang bisa diamati ke yang bisa diamati. Peta item peta ke item.
Flatmap lebih fleksibel tetapi Map lebih ringan dan langsung, jadi itu tergantung pada penggunaan Anda.
Jika Anda melakukan APA SAJA async (termasuk mengganti utas), Anda harus menggunakan Flatmap, karena Map tidak akan memeriksa apakah konsumen dibuang (bagian dari yang ringan)
sumber