Ini adalah repositori dengan contoh nyata penggunaan RxJava dengan Android. Biasanya akan berada dalam status "Pekerjaan dalam Proses" (WIP) yang konstan.
Saya juga telah memberikan ceramah tentang Belajar Rx menggunakan banyak contoh yang tercantum dalam repo ini.
using
)Persyaratan umum adalah memindahkan operasi intensif I/O berat yang panjang ke thread latar belakang (thread non-UI) dan memasukkan hasilnya kembali ke UI/thread utama, setelah selesai. Ini adalah demo tentang bagaimana operasi yang berjalan lama dapat dipindahkan ke thread latar belakang. Setelah operasi selesai, kami melanjutkan kembali ke thread utama. Semua menggunakan RxJava! Anggap saja ini sebagai pengganti AsyncTasks.
Operasi panjang disimulasikan dengan panggilan Thread.sleep yang memblokir (karena ini dilakukan di thread latar belakang, UI kami tidak pernah terganggu).
Untuk benar-benar melihat contoh ini bersinar. Tekan tombol beberapa kali dan lihat bagaimana klik tombol (yang merupakan operasi UI) tidak pernah diblokir karena operasi lama hanya berjalan di latar belakang.
Ini adalah demo bagaimana peristiwa dapat diakumulasikan menggunakan operasi "buffer".
Sebuah tombol disediakan dan kami mengumpulkan jumlah klik pada tombol itu, selama rentang waktu tertentu dan kemudian mengeluarkan hasil akhirnya.
Jika Anda menekan tombol sekali, Anda akan mendapat pesan yang menyatakan bahwa tombol telah ditekan sekali. Jika Anda menekannya 5 kali terus-menerus dalam kurun waktu 2 detik, Anda akan mendapatkan satu log yang menyatakan bahwa Anda menekan tombol itu 5 kali (vs 5 log individual yang mengatakan "Tombol tekan sekali").
Catatan:
Jika Anda mencari solusi yang lebih mudah yang mengumpulkan ketukan "terus menerus" vs hanya jumlah ketukan dalam rentang waktu tertentu, lihat Demo EventBus yang menggunakan kombinasi operator publish
dan buffer
. Untuk penjelasan lebih detailnya, Anda juga bisa melihat pada postingan blog ini.
Ini adalah demo tentang bagaimana peristiwa dapat ditelan sedemikian rupa sehingga hanya peristiwa terakhir saja yang dihormati. Contoh tipikalnya adalah kotak hasil pencarian instan. Saat Anda mengetik kata "Bruce Lee", Anda tidak ingin menjalankan pencarian untuk B, Br, Bru, Bruce, Bruce, Bruce L ... dll. Namun dengan cerdas menunggu beberapa saat, pastikan pengguna telah selesai mengetik seluruh kata, lalu mengeluarkan satu panggilan untuk "Bruce Lee".
Saat Anda mengetik di kotak masukan, ia tidak akan mengeluarkan pesan log pada setiap perubahan karakter masukan, melainkan hanya memilih peristiwa yang terakhir dikeluarkan (yaitu masukan) dan mencatatnya.
Ini adalah metode debounce/throttleWithTimeout di RxJava.
Retrofit from Square adalah perpustakaan luar biasa yang membantu jaringan mudah (bahkan jika Anda belum beralih ke RxJava, Anda benar-benar harus memeriksanya). Ia bekerja lebih baik lagi dengan RxJava dan ini adalah contoh mengenai API GitHub, yang diambil langsung dari pembicaraan pengembang setengah dewa android Jake Wharton di Netflix. Anda dapat menyaksikan ceramahnya di tautan ini. Kebetulan, motivasi saya menggunakan RxJava adalah dari menghadiri pembicaraan di Netflix ini.
(Catatan: kemungkinan besar Anda akan mencapai kuota GitHub API dengan cukup cepat, jadi kirimkan token OAuth sebagai parameter jika Anda ingin terus menjalankan contoh ini sesering mungkin).
Tampilan yang diperbarui secara otomatis adalah hal yang cukup keren. Jika Anda pernah berurusan dengan Angular JS sebelumnya, mereka memiliki konsep yang cukup bagus yang disebut "pengikatan data dua arah", jadi ketika elemen HTML diikat ke objek model/entitas, elemen tersebut terus-menerus "mendengarkan" perubahan pada entitas tersebut dan memperbarui statusnya secara otomatis berdasarkan model. Dengan menggunakan teknik dalam contoh ini, Anda berpotensi menggunakan pola seperti pola Model Tampilan Presentasi dengan sangat mudah.
Meskipun contoh di sini masih sederhana, teknik yang digunakan untuk mencapai pengikatan ganda menggunakan Publish Subject
jauh lebih menarik.
Ini adalah contoh polling menggunakan RxJava Scheduler. Ini berguna jika Anda ingin terus-menerus melakukan polling pada server dan mungkin mendapatkan data baru. Panggilan jaringan "disimulasikan" sehingga memaksa penundaan sebelum mengembalikan string yang dihasilkan.
Ada dua varian untuk ini:
Contoh kedua pada dasarnya adalah varian dari Exponential Backoff.
Daripada menggunakan RetryWithDelay, kami menggunakan RepeatWithDelay di sini. Untuk memahami perbedaan antara Coba Lagi(Kapan) dan Ulangi(Kapan), saya akan menyarankan postingan fantastis Dan tentang subjek ini.
Pendekatan alternatif untuk menunda pemungutan suara tanpa menggunakan repeatWhen
adalah dengan menggunakan pengamatan penundaan yang dirangkai dan dirangkai. Lihat startExecutingWithExponentialBackoffDelay dalam contoh ExponentialBackOffFragment.
Backoff eksponensial adalah strategi yang berdasarkan umpan balik dari keluaran tertentu, kami mengubah laju suatu proses (biasanya mengurangi jumlah percobaan ulang atau menambah waktu tunggu sebelum mencoba ulang atau menjalankan kembali proses tertentu).
Konsep ini lebih masuk akal jika diberikan contoh. RxJava membuatnya (relatif) mudah untuk menerapkan strategi seperti itu. Terima kasih saya kepada Mike karena telah menyarankan gagasan itu.
Katakanlah Anda mengalami kegagalan jaringan. Strategi yang masuk akal adalah JANGAN terus mencoba ulang panggilan jaringan Anda setiap 1 detik. Akan lebih cerdas (tidak... elegan!) untuk mencoba lagi dengan penundaan yang semakin lama. Jadi Anda mencoba pada detik 1 untuk menjalankan panggilan jaringan, tanpa dadu? coba setelah 10 detik...negatif? coba setelah 20 detik, tidak ada cookie? coba setelah 1 menit. Jika hal ini masih gagal, Anda harus menyerah pada jaringan yo!
Kami mensimulasikan perilaku ini menggunakan RxJava dengan operator retryWhen
.
Cuplikan kode RetryWithDelay
milik:
Lihat juga contoh Polling di mana kita menggunakan mekanisme backoff Eksponensial yang sangat mirip.
Varian lain dari strategi backoff eksponensial adalah mengeksekusi suatu operasi selama beberapa kali tertentu tetapi dengan interval yang tertunda. Jadi Anda menjalankan operasi tertentu 1 detik dari sekarang, lalu Anda menjalankannya lagi 10 detik dari sekarang, lalu Anda menjalankan operasi tersebut 20 detik dari sekarang. Setelah total 3 kali Anda berhenti mengeksekusi.
Mensimulasikan perilaku ini sebenarnya jauh lebih sederhana daripada mekanisme percobaan ulang sebelumnya. Anda dapat menggunakan varian operator delay
untuk mencapai hal ini.
.combineLatest
)Terima kasih kepada Dan Lew karena telah memberi saya ide ini di podcast terfragmentasi - episode #4 (sekitar pukul 4:30).
.combineLatest
memungkinkan Anda memantau status beberapa observasi sekaligus secara kompak di satu lokasi. Contoh yang ditunjukkan menunjukkan bagaimana Anda dapat menggunakan .combineLatest
untuk memvalidasi formulir dasar. Ada 3 masukan utama agar formulir ini dianggap "valid" (email, kata sandi, dan nomor). Formulir akan menjadi valid (teks di bawah berubah menjadi biru :P) setelah semua input valid. Jika tidak, kesalahan akan ditampilkan pada input yang tidak valid.
Kami memiliki 3 observasi independen yang melacak perubahan teks/input untuk setiap bidang formulir ( WidgetObservable
RxAndroid berguna untuk memantau perubahan teks). Setelah perubahan peristiwa diketahui dari ketiga input, hasilnya "digabungkan" dan formulir dievaluasi validitasnya.
Perhatikan bahwa fungsi Func3
yang memeriksa validitas, aktif hanya setelah SEMUA 3 input menerima peristiwa perubahan teks.
Nilai dari teknik ini menjadi lebih jelas ketika Anda memiliki lebih banyak jumlah kolom input dalam suatu formulir. Menanganinya sebaliknya dengan sekumpulan boolean membuat kode menjadi berantakan dan sulit diikuti. Tetapi menggunakan .combineLatest
semua logika itu terkonsentrasi dalam blok kode kompak yang bagus (saya masih menggunakan boolean tapi itu untuk membuat contoh lebih mudah dibaca).
Kami memiliki dua sumber yang Dapat Diamati: cache disk (cepat) dan panggilan jaringan (baru). Biasanya disk Observable jauh lebih cepat daripada jaringan Observable. Namun untuk mendemonstrasikan cara kerjanya, kami juga menggunakan cache disk palsu yang "lebih lambat" hanya untuk melihat bagaimana perilaku operator.
Hal ini ditunjukkan dengan menggunakan 4 teknik:
.concat
.concatEager
.merge
.publish
pemilih + gabungkan + ambil HinggaTeknik ke-4 mungkin adalah teknik yang ingin Anda gunakan pada akhirnya, tetapi menarik untuk menelusuri perkembangan tekniknya, untuk memahami alasannya.
concat
itu bagus. Ini mengambil informasi dari Observable pertama (cache disk dalam kasus kami) dan kemudian jaringan Observable berikutnya. Karena cache disk mungkin lebih cepat, semuanya tampak baik-baik saja dan cache disk dimuat dengan cepat, dan setelah panggilan jaringan selesai, kami menukar hasil "segar".
Masalah dengan concat
adalah bahwa observasi berikutnya bahkan tidak dimulai sampai Observable pertama selesai. Itu bisa menjadi masalah. Kami ingin semua observasi dimulai secara bersamaan tetapi memberikan hasil sesuai yang kami harapkan. Untungnya RxJava memperkenalkan concatEager
yang melakukan hal itu. Ini memulai kedua observasi tetapi menyangga hasil dari observasi terakhir hingga Observable sebelumnya selesai. Ini adalah pilihan yang sepenuhnya layak.
Namun terkadang, Anda hanya ingin segera menunjukkan hasilnya. Dengan asumsi observasi pertama (untuk beberapa alasan aneh) membutuhkan waktu sangat lama untuk menjalankan semua itemnya, bahkan jika beberapa item pertama dari observasi kedua telah gagal, item tersebut akan dimasukkan dalam antrean secara paksa. Anda tidak perlu "menunggu" di Observable mana pun. Dalam situasi ini, kita dapat menggunakan operator merge
. Ini menyisipkan item saat dipancarkan. Ini berfungsi dengan baik dan mulai mengeluarkan hasilnya segera setelah ditampilkan.
Mirip dengan operator concat
, jika Observable pertama Anda selalu lebih cepat daripada Observable kedua, Anda tidak akan mengalami masalah apa pun. Namun masalah dengan merge
adalah: jika karena alasan aneh suatu item dikeluarkan oleh cache atau diamati lebih lambat setelah pengamatan yang lebih baru/lebih segar, itu akan menimpa konten yang lebih baru. Klik tombol "MERGE (SLOWER DISK)" pada contoh untuk melihat masalah ini beraksi. Kontribusi @JakeWharton dan @swankjesse menjadi 0! Di dunia nyata, hal ini bisa berdampak buruk, karena ini berarti data baru akan digantikan oleh data disk yang sudah usang.
Untuk mengatasi masalah ini, Anda dapat menggunakan penggabungan dalam kombinasi dengan operator publish
super bagus yang menggunakan "pemilih". Saya menulis tentang penggunaan ini di posting blog tetapi saya harus berterima kasih kepada Jedi JW karena telah mengingatkan teknik ini. Kami publish
jaringan yang dapat diamati dan menyediakan pemilih yang mulai memancarkan dari cache disk, hingga jaringan yang dapat diamati mulai memancarkan. Setelah jaringan yang dapat diamati mulai memancarkan, ia akan mengabaikan semua hasil dari disk yang dapat diamati. Ini sempurna dan menangani masalah apa pun yang mungkin kita hadapi.
Sebelumnya saya menggunakan operator merge
tetapi mengatasi masalah hasil tertimpa dengan memonitor "resultAge". Lihat contoh PseudoCacheMergeFragment
lama jika Anda penasaran melihat implementasi lama ini.
Ini adalah contoh super sederhana dan lugas yang menunjukkan kepada Anda cara menggunakan operator timer
, interval
, dan delay
RxJava untuk menangani banyak kasus di mana Anda ingin menjalankan tugas pada interval tertentu. Pada dasarnya katakan TIDAK pada Android TimerTask
s.
Kasus-kasus yang ditunjukkan di sini:
Ada postingan blog terlampir yang menjelaskan detail demo ini dengan lebih baik:
Pertanyaan umum yang ditanyakan saat menggunakan RxJava di Android adalah, "bagaimana cara melanjutkan pekerjaan yang dapat diamati jika terjadi perubahan konfigurasi (rotasi aktivitas, perubahan bahasa lokal, dll.)?".
Contoh ini menunjukkan kepada Anda satu strategi yaitu. menggunakan Fragmen yang dipertahankan. Saya mulai menggunakan fragmen yang disimpan sebagai "fragmen pekerja" setelah membaca postingan fantastis dari Alex Lockwood beberapa waktu lalu.
Tekan tombol start dan putar layar sesuka hati Anda; Anda akan melihat observasi berlanjut dari titik terakhirnya.
Ada keanehan tertentu tentang "panasnya" sumber yang dapat diamati yang digunakan dalam contoh ini. Lihat posting blog saya di mana saya menjelaskan secara spesifik.
Saya telah menulis ulang contoh ini menggunakan pendekatan alternatif. Meskipun pendekatan ConnectedObservable
berhasil, pendekatan ini memasuki bidang "multicasting" yang mungkin rumit (keamanan thread, .refcount, dll.). Sebaliknya, subjeknya jauh lebih sederhana. Anda dapat melihatnya ditulis ulang menggunakan Subject
di sini.
Saya menulis posting blog lain tentang cara berpikir tentang Subjek di mana saya membahas beberapa hal secara spesifik.
Volley adalah perpustakaan jaringan lain yang diperkenalkan oleh Google di IO '13. Warga github yang baik hati menyumbangkan contoh ini sehingga kami tahu cara mengintegrasikan Volley dengan RxJava.
Saya memanfaatkan penggunaan Subjek yang sederhana di sini. Sejujurnya, jika item Anda belum diturunkan melalui Observable
(seperti melalui Retrofit atau permintaan jaringan), tidak ada alasan bagus untuk menggunakan Rx dan memperumit masalah.
Contoh ini pada dasarnya mengirimkan nomor halaman ke Subjek, dan subjek menangani penambahan item. Perhatikan penggunaan concatMap
dan kembalinya Observable<List>
dari _itemsFromNetworkCall
.
Sebagai permulaan, saya juga menyertakan contoh PaginationAutoFragment
, "penomoran halaman otomatis" ini tanpa kita perlu menekan tombol. Seharusnya mudah diikuti jika Anda memahami cara kerja contoh sebelumnya.
Berikut adalah beberapa implementasi mewah lainnya (walaupun saya senang membacanya, saya tidak menggunakannya untuk aplikasi dunia nyata karena menurut saya pribadi itu tidak perlu):
Diagram ascii di bawah ini mengungkapkan maksud dari contoh berikutnya dengan panache. f1,f2,f3,f4,f5 pada dasarnya adalah panggilan jaringan yang ketika dilakukan, memberikan kembali hasil yang diperlukan untuk perhitungan di masa depan.
(flatmap)
f1 ___________________ f3 _______
(flatmap) | (zip)
f2 ___________________ f4 _______| ___________ final output
|
____________ f5 _______|
Kode untuk contoh ini telah ditulis oleh salah satu Mr.skehlet di interwebs. Buka inti kodenya. Itu ditulis dalam Java murni (6) jadi cukup mudah dipahami jika Anda sudah memahami contoh sebelumnya. Saya akan membahasnya lagi di sini jika waktu mengizinkan atau saya sudah kehabisan contoh menarik lainnya.
Ini adalah contoh sederhana yang menunjukkan penggunaan operator .timeout
. Tombol 1 akan menyelesaikan tugas sebelum batas waktu habis, sedangkan Tombol 2 akan memaksakan kesalahan batas waktu.
Perhatikan bagaimana kami dapat menyediakan Observable kustom yang menunjukkan bagaimana bereaksi di bawah Pengecualian batas waktu.
using
) Operator using
relatif kurang dikenal dan terkenal sulit bagi Google. Ini adalah API indah yang membantu menyiapkan sumber daya (mahal), menggunakannya, dan kemudian membuangnya dengan cara yang bersih.
Hal yang menyenangkan tentang operator ini adalah ia menyediakan mekanisme untuk menggunakan sumber daya yang berpotensi mahal dalam cakupan yang ketat. menggunakan -> pengaturan, gunakan dan buang. Pikirkan koneksi DB (seperti instance Realm), koneksi soket, kunci thread, dll.
Multicasting di Rx seperti seni gelap. Tidak banyak orang yang tahu cara melakukannya tanpa rasa khawatir. Contoh ini menggabungkan dua pelanggan (dalam bentuk tombol) dan memungkinkan Anda menambah/menghapus pelanggan pada titik waktu yang berbeda dan melihat bagaimana perilaku operator yang berbeda dalam keadaan tersebut.
Observale sumber adalah pengatur waktu ( interval
) yang dapat diamati dan alasan pemilihan ini adalah karena sengaja memilih observasi yang tidak dapat dihentikan, sehingga Anda dapat menguji/mengonfirmasi apakah eksperimen multicast Anda akan bocor.
Saya juga memberikan ceramah tentang Multicasting secara detail di 360|Andev. Jika Anda punya keinginan dan waktu, saya sangat menyarankan untuk menonton pembicaraan itu terlebih dahulu (khususnya segmen permutasi operator Multicast) dan kemudian bermain-main dengan contoh di sini.
Semua contoh di sini telah dimigrasikan untuk menggunakan RxJava 2.X.
Kami menggunakan perpustakaan Interop David Karnok dalam beberapa kasus karena perpustakaan tertentu seperti RxBindings, RxRelays, RxJava-Math dll. belum di-porting ke 2.x.
Saya mencoba memastikan contoh-contoh tersebut tidak dibuat-buat tetapi mencerminkan kasus penggunaan di dunia nyata. Jika Anda memiliki contoh berguna serupa yang menunjukkan penggunaan RxJava, silakan kirimkan permintaan penarikan.
Saya juga sedang mempelajari RxJava, jadi jika Anda merasa ada cara yang lebih baik untuk melakukan salah satu contoh yang disebutkan di atas, bukalah terbitan yang menjelaskan caranya. Lebih baik lagi, kirimkan permintaan tarik.
Rx threading adalah bisnis yang berantakan. Untuk membantu, proyek ini menggunakan alat YourKit untuk analisis.
YourKit mendukung proyek sumber terbuka dengan alat inovatif dan cerdas untuk memantau dan membuat profil aplikasi Java. YourKit adalah pencipta YourKit Java Profiler.
Berlisensi di bawah Lisensi Apache, Versi 2.0 ("Lisensi"). Anda dapat memperoleh salinan Lisensi di
http://www.apache.org/licenses/LICENSE-2.0
Kecuali diwajibkan oleh undang-undang yang berlaku atau disetujui secara tertulis, perangkat lunak yang didistribusikan berdasarkan Lisensi didistribusikan berdasarkan DASAR "APA ADANYA", TANPA JAMINAN ATAU KETENTUAN DALAM BENTUK APAPUN, baik tersurat maupun tersirat. Lihat Lisensi untuk bahasa tertentu yang mengatur izin dan batasan berdasarkan Lisensi.
Anda setuju bahwa semua kontribusi pada repositori ini, dalam bentuk perbaikan, permintaan tarik, contoh baru, dll., mengikuti lisensi yang disebutkan di atas.