Saya sedang mengerjakan jaringan untuk aplikasi saya. Jadi saya memutuskan untuk mencoba Square's Retrofit . Saya melihat bahwa mereka mendukung sederhanaCallback
@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);
dan RxJava Observable
@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);
Keduanya terlihat sangat mirip pada pandangan pertama, tetapi ketika sampai pada implementasi itu menjadi menarik ...
Sementara dengan implementasi callback sederhana akan terlihat mirip dengan ini:
api.getUserPhoto(photoId, new Callback<Photo>() {
@Override
public void onSuccess() {
}
});
yang cukup sederhana dan mudah. Dan dengan Observable
itu cepat menjadi verbose dan cukup rumit.
public Observable<Photo> getUserPhoto(final int photoId) {
return Observable.create(new Observable.OnSubscribeFunc<Photo>() {
@Override
public Subscription onSubscribe(Observer<? super Photo> observer) {
try {
observer.onNext(api.getUserPhoto(photoId));
observer.onCompleted();
} catch (Exception e) {
observer.onError(e);
}
return Subscriptions.empty();
}
}).subscribeOn(Schedulers.threadPoolForIO());
}
Dan bukan itu. Anda masih harus melakukan sesuatu seperti ini:
Observable.from(photoIdArray)
.mapMany(new Func1<String, Observable<Photo>>() {
@Override
public Observable<Photo> call(Integer s) {
return getUserPhoto(s);
}
})
.subscribeOn(Schedulers.threadPoolForIO())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Photo>() {
@Override
public void call(Photo photo) {
//save photo?
}
});
Apakah saya melewatkan sesuatu di sini? Atau apakah ini kasus yang salah untuk digunakan Observable
? Kapan seseorang harus / Observable
lebih suka daripada Callback sederhana?
Memperbarui
Menggunakan retrofit jauh lebih sederhana daripada contoh di atas seperti yang ditunjukkan @Niels dalam jawabannya atau dalam contoh proyek Jake Wharton U2020 . Tetapi pada dasarnya pertanyaannya tetap sama - kapan satu harus menggunakan satu cara atau yang lain?
Jawaban:
Untuk hal-hal jaringan yang sederhana, kelebihan RxJava dibandingkan Callback sangat terbatas. Contoh getUserPhoto sederhana:
RxJava:
Telepon balik:
Varian RxJava tidak jauh lebih baik daripada varian Callback. Untuk saat ini, mari kita abaikan penanganan kesalahan. Mari kita ambil daftar foto:
RxJava:
Telepon balik:
Sekarang, varian RxJava masih tidak lebih kecil, meskipun dengan Lambdas akan lebih dekat dengan varian Callback. Selain itu, jika Anda memiliki akses ke umpan JSON, akan agak aneh untuk mengambil semua foto saat Anda hanya menampilkan PNG. Sesuaikan feed agar hanya menampilkan PNG.
Kesimpulan pertama
Itu tidak membuat basis kode Anda lebih kecil ketika Anda memuat JSON sederhana yang Anda siapkan dalam format yang tepat.
Sekarang, mari kita buat hal-hal sedikit lebih menarik. Katakanlah Anda tidak hanya ingin mengambil userPhoto, tetapi Anda memiliki kloning-Instagram, dan Anda ingin mengambil 2 JSON: 1. getUserDetails () 2. getUserPhotos ()
Anda ingin memuat kedua JSON ini secara paralel, dan ketika keduanya dimuat, halaman tersebut harus ditampilkan. Varian panggilan balik akan menjadi sedikit lebih sulit: Anda harus membuat 2 panggilan balik, menyimpan data dalam aktivitas, dan jika semua data dimuat, tampilkan halaman:
Telepon balik:
RxJava:
Kami pergi ke suatu tempat! Kode RxJava sekarang sebesar opsi callback. Kode RxJava lebih kuat; Pikirkan apa yang akan terjadi jika kita membutuhkan JSON ketiga untuk dimuat (seperti Video terbaru)? RxJava hanya perlu sedikit penyesuaian, sedangkan varian Callback perlu disesuaikan di beberapa tempat (pada setiap panggilan balik kita perlu memeriksa apakah semua data diambil).
Contoh lain; kami ingin membuat bidang pelengkapan otomatis, yang memuat data menggunakan Retrofit. Kami tidak ingin melakukan panggilan web setiap kali EditText memiliki TextChangedEvent. Saat mengetik cepat, hanya elemen terakhir yang harus memicu panggilan. Pada RxJava kita dapat menggunakan operator debounce:
Saya tidak akan membuat varian Callback tetapi Anda akan mengerti ini jauh lebih sulit.
Kesimpulan: RxJava sangat baik ketika data dikirim sebagai aliran. Retrofit Observable mendorong semua elemen pada aliran pada saat yang bersamaan. Ini tidak terlalu berguna dalam dirinya sendiri dibandingkan dengan Callback. Tetapi ketika ada beberapa elemen yang didorong pada aliran dan waktu yang berbeda, dan Anda perlu melakukan hal-hal yang berhubungan dengan waktu, RxJava membuat kode jauh lebih mudah dikelola.
sumber
inputObservable
? Saya memiliki banyak masalah dengan debouncing dan ingin belajar lebih banyak tentang solusi ini.RxView
,RxTextView
dll yang dapat digunakan untukinputObservable
.Hal-hal yang Dapat Diamati sudah dilakukan di Retrofit, jadi kodenya bisa seperti ini:
sumber
Callback
Anda dapat berhenti berlanggananObserveable
, karena itu menghindari masalah daur hidup umum.Dalam kasus getUserPhoto () keuntungan untuk RxJava tidak bagus. Tapi mari kita ambil contoh lain ketika Anda akan mendapatkan semua foto untuk pengguna, tetapi hanya ketika gambar adalah PNG, dan Anda tidak memiliki akses ke JSON untuk melakukan pemfilteran di sisi server.
Sekarang JSON mengembalikan daftar Photo. Kami akan flatMap mereka ke item individual. Dengan melakukannya, kita akan dapat menggunakan metode filter untuk mengabaikan foto yang bukan PNG. Setelah itu, kami akan berlangganan, dan mendapatkan panggilan balik untuk setiap foto, errorHandler, dan panggilan balik ketika semua baris telah selesai.
Titik TLDR di sini adalah; panggilan balik hanya mengembalikan Anda panggilan balik untuk keberhasilan dan kegagalan; Observasi RxJava memungkinkan Anda melakukan peta, mengurangi, memfilter, dan banyak hal lainnya.
sumber
Dengan rxjava Anda dapat melakukan lebih banyak hal dengan lebih sedikit kode.
Mari kita asumsikan bahwa Anda ingin menerapkan pencarian instan di aplikasi Anda. Dengan panggilan balik, Anda khawatir tentang berhenti berlangganan permintaan sebelumnya dan berlangganan yang baru, menangani perubahan orientasi sendiri ... Saya pikir itu banyak kode dan terlalu bertele-tele.
Dengan rxjava sangat sederhana.
jika Anda ingin menerapkan pencarian instan, Anda hanya perlu mendengarkan TextChangeListener dan menelepon
photoModel.setUserId(EditText.getText());
Dalam metode Fragmen atau aktivitas onCreate Anda berlangganan Observable yang mengembalikan photoModel.subscribeToPhoto (), ia mengembalikan Observable yang selalu memancarkan item yang dipancarkan oleh Observable terbaru (permintaan).
Juga, jika PhotoModel adalah Singleton, misalnya, Anda tidak perlu khawatir tentang perubahan orientasi, karena BehaviorSubject memancarkan respons server terakhir, terlepas dari kapan Anda berlangganan.
Dengan baris kode ini kami telah menerapkan pencarian instan dan menangani perubahan orientasi. Apakah Anda pikir Anda dapat menerapkan ini dengan panggilan balik dengan kode lebih sedikit? Aku meragukan itu.
sumber
Kami biasanya menggunakan logika berikut:
sumber
Dengan sampel dan kesimpulan dalam jawaban lain, saya pikir tidak ada perbedaan besar untuk tugas sederhana satu atau dua langkah. Namun, Callback sederhana dan mudah. RxJava lebih rumit dan terlalu besar untuk tugas sederhana. Ada solusi ketiga oleh: AbacusUtil . Biarkan saya menerapkan kasus penggunaan di atas dengan ketiga solusi: Callback, RxJava, CompletableFuture (AbacusUtil) dengan Retrolambda :
Ambil foto dari jaringan dan simpan / tampilkan di perangkat:
Muat detail pengguna dan foto secara paralel
sumber
Saya pribadi lebih suka menggunakan Rx untuk mendapatkan respons api dalam kasus yang harus saya lakukan filter, peta atau sesuatu seperti itu pada data Atau dalam kasus bahwa saya harus melakukan panggilan api lain berdasarkan respons panggilan sebelumnya
sumber
Sepertinya Anda menciptakan kembali roda, apa yang Anda lakukan sudah diterapkan di retrofit.
Sebagai contoh, Anda bisa melihat RestAdapterTest.java retrofit , di mana mereka mendefinisikan antarmuka dengan Observable sebagai tipe pengembalian, dan kemudian menggunakannya .
sumber
Saat Anda membuat aplikasi untuk bersenang-senang, proyek kesayangan, atau POC atau prototipe ke-1 Anda menggunakan kelas inti android / java sederhana seperti callback, tugas async, looper, utas, dll. Mereka mudah digunakan dan tidak memerlukan apa pun Integrasi lib pihak ketiga. Integrasi perpustakaan besar hanya untuk membangun proyek kecil yang tidak dapat diubah adalah tidak masuk akal ketika hal serupa dapat dilakukan dengan benar.
Namun, ini seperti pisau yang sangat tajam. Menggunakan ini dalam lingkungan produksi selalu keren tetapi juga mereka akan memiliki konsekuensi. Sulit untuk menulis kode konkuren yang aman jika Anda tidak berpengalaman dengan prinsip pengkodean Bersih dan SOLID. Anda harus mempertahankan arsitektur yang tepat untuk memfasilitasi perubahan di masa depan dan meningkatkan produktivitas tim.
Di sisi lain, pustaka konkurensi seperti RxJava, Co-rutin dll dicoba dan diuji lebih dari satu miliar kali untuk membantu menulis kode konkursi yang siap-produksi. Sekarang lagi, bukan dengan menggunakan pustaka-pustaka ini Anda tidak menulis kode bersamaan atau mengabstraksi semua logika konkurensi. Kamu masih. Tapi sekarang, itu terlihat dan memberlakukan pola yang jelas untuk menulis kode bersamaan di seluruh basis kode dan yang lebih penting di seluruh tim pengembangan Anda.
Ini adalah manfaat utama menggunakan kerangka kerja konkurensi alih-alih kelas inti lama sederhana yang berhubungan dengan konkurensi mentah. Namun, jangan salah paham. Saya sangat percaya dalam membatasi dependensi perpustakaan eksternal tetapi dalam kasus khusus ini, Anda harus membangun kerangka kerja kustom untuk basis kode Anda yang merupakan tugas yang memakan waktu dan dapat dilakukan hanya setelah pengalaman sebelumnya. Oleh karena itu, kerangka kerja konkurensi lebih disukai daripada menggunakan kelas biasa seperti callback, dll.
TL'DR
Jika Anda sudah menggunakan RxJava untuk pengkodean bersamaan di seluruh basis kode, cukup gunakan RxJava Observable / Flowable. Pertanyaan bijak untuk ditanyakan adalah apakah saya harus menggunakan Observables untuk Flowables. Jika tidak, lanjutkan dan gunakan callable.
sumber