Artikel ini akan membahas 
RxJava2 di 
RxJava2 versi 
2.0.6 dan yang lebih baru. Jika seseorang bertabrakan dan tidak bisa mengetahuinya, atau sama sekali tidak mendengar masalah ini - saya minta kucing. Mereka mendorong terjemahan masalah dalam 
production setelah transisi dari 
RxJava1 ke 
RxJava2 . Dokumen asli ditulis pada 28 Desember 2017, tetapi lebih baik untuk mencari tahu terlambat daripada tidak sama sekali.
Kita semua adalah pengembang yang baik dan menangkap kesalahan di 
onError ketika kita menggunakan 
RxJava . Ini berarti bahwa kami telah melindungi diri dari gangguan aplikasi, bukan?
Tidak, tidak benar.Di bawah ini kita akan melihat beberapa contoh di mana aplikasi akan 
RxJava karena 
RxJava , bahkan jika 
onError diimplementasikan dengan benar.
Basic Error Handler di RxJava
RxJava menggunakan 
RxJavaPlugins.onError sebagai pengendali kesalahan dasar. Ini menangani semua kesalahan yang tidak bisa dikirim ke pelanggan. Secara default, semua kesalahan dikirim ke sana, sehingga crash aplikasi kritis dapat terjadi.
2.0.6 menggambarkan perilaku ini:
Salah satu tujuan dari desain 2.x adalah kurangnya kesalahan yang hilang. Terkadang urutan berakhir atau dibatalkan sebelum sumber meningkatkan onError . Dalam hal ini, kesalahan tidak memiliki tempat untuk pergi dan dikirim ke RxJavaPlugins.onError
Jika RxJava tidak memiliki penangan kesalahan dasar, kesalahan seperti itu akan disembunyikan dari kami dan pengembang akan berada dalam kegelapan tentang potensi masalah dalam kode.
Dimulai dengan versi 
2.0.6 , 
RxJavaPlugins.onError mencoba menjadi lebih cerdas dan berbagi pustaka / kesalahan implementasi dan situasi saat kesalahan tidak dapat disampaikan. Kesalahan yang diberikan pada kategori "bug" disebut apa adanya, sedangkan sisanya dibungkus dalam 
UndeliverableException dan kemudian dipanggil. Anda dapat melihat semua logika ini di 
sini ( 
isBug dan 
isBug ).
Salah satu kesalahan utama pemula dalam 
RxJava OnErrorNotImplementedException adalah 
OnErrorNotImplementedException . Kesalahan ini terjadi jika 
observable menyebabkan kesalahan dan metode 
onError tidak diterapkan pada pelanggan. Kesalahan ini adalah contoh kesalahan yang untuk penangan kesalahan dasar 
RxJava adalah "bug" dan tidak berubah menjadi 
UndeliverableException .
Pengecualian tidak terkirim
Karena kesalahan yang terkait dengan "bug" mudah diperbaiki, kami tidak akan membahasnya. Kesalahan yang 
RxJava bungkus dalam 
RxJava lebih menarik, karena mungkin tidak selalu jelas mengapa kesalahan tidak dapat dikirim ke 
onError .
Kasus-kasus di mana hal ini dapat terjadi tergantung pada apa yang dilakukan sumber dan pelanggan secara khusus. Kami akan mempertimbangkan contoh-contoh di bawah ini, tetapi secara umum kami dapat mengatakan bahwa kesalahan semacam itu terjadi jika tidak ada pelanggan aktif kepada siapa kesalahan tersebut dapat disampaikan.
Contoh dengan zipWith ()
Opsi pertama di mana Anda dapat meningkatkan 
zipWith .
 val observable1 = Observable.error<Int>(Exception()) val observable2 = Observable.error<Int>(Exception()) val zipper = BiFunction<Int, Int, String> { one, two -> "$one - $two" } observable1.zipWith(observable2, zipper) .subscribe( { System.out.println(it) }, { it.printStackTrace() } ) 
Kami menggabungkan dua sumber bersama-sama, yang masing-masing menyebabkan kesalahan. Apa yang kita harapkan Kita dapat mengasumsikan bahwa 
onError akan dipanggil dua kali, tetapi ini bertentangan 
dengan spesifikasi Reactive streams .
Setelah satu panggilan ke acara terminal ( onError , onCompelete ), diperlukan bahwa tidak ada lagi panggilan yang dilakukan
Ternyata dengan satu panggilan ke 
onError panggilan kedua tidak lagi mungkin. Apa yang terjadi ketika kesalahan kedua terjadi di sumber? Ini akan dikirimkan ke 
RxJavaPlugins.onError .
Cara mudah untuk masuk ke situasi ini adalah dengan menggunakan 
zip untuk menggabungkan panggilan jaringan (misalnya, dua panggilan 
Retrofit Observable ). Jika kesalahan terjadi di kedua panggilan (misalnya, tidak ada koneksi Internet), kedua sumber akan menyebabkan kesalahan, yang pertama akan jatuh ke dalam implementasi 
onError , dan yang kedua akan dikirim ke penangan kesalahan dasar ( 
RxJavaPlugins.onError ).
Contoh ConnectableObservable tanpa pelanggan
ConnectableObservable juga dapat meningkatkan 
UndeliverableException . Patut diingat bahwa 
ConnectableObservable memunculkan peristiwa terlepas dari keberadaan pelanggan aktif, panggil saja metode 
connect() . Jika kesalahan terjadi di 
ConnectableObservable ketika tidak ada pelanggan, itu akan dikirimkan ke penangan kesalahan dasar.
Berikut adalah contoh yang sangat tidak bersalah yang dapat menyebabkan kesalahan seperti itu:
 someApi.retrofitCall()  
Jika 
someApi.retrofitCall() menyebabkan kesalahan (misalnya, tidak ada koneksi Internet), aplikasi akan macet karena kesalahan jaringan akan dikirim ke 
RxJava kesalahan dasar 
RxJava .
Contoh ini tampaknya fiktif, tetapi sangat mudah untuk masuk ke situasi di mana 
ConnectableObservable masih terhubung, tetapi tidak memiliki pelanggan. Saya menemukan ini ketika menggunakan 
autoConnect() saat memanggil API. 
autoConnect() tidak secara otomatis menonaktifkan 
Observable . Saya berhenti berlangganan dalam metode 
Activity onStop , tetapi hasil panggilan jaringan kembali setelah penghancuran 
Activity dan aplikasi 
UndeliverableException dengan 
UndeliverableException .
Menangani kesalahan
Jadi apa yang harus dilakukan dengan kesalahan ini?
Langkah pertama adalah melihat kesalahan yang terjadi dan mencoba menentukan apa yang menyebabkannya. Idealnya, jika Anda dapat memperbaiki masalah pada sumbernya untuk mencegah kesalahan dari 
RxJavaPlugins.onError ke 
RxJavaPlugins.onError .
Solusi untuk contoh 
zipWith adalah dengan mengambil satu atau kedua sumber dan mengimplementasikan 
salah satu metode untuk menangkap kesalahan di dalamnya. Misalnya, Anda dapat menggunakan 
onErrorReturn untuk meneruskan nilai default alih-alih kesalahan.
Contoh 
ConnectableObservable lebih mudah untuk diperbaiki - hanya pastikan Anda memutuskan 
Observable ketika pelanggan terakhir berhenti berlangganan. 
autoConnect() , misalnya, memiliki implementasi kelebihan beban yang mengambil fungsi yang menangkap waktu koneksi ( 
lebih banyak dapat dilihat di sini ).
Cara lain untuk memecahkan masalah adalah mengganti handler kesalahan dasar dengan Anda sendiri. Metode 
RxJavaPlugins.setErrorHandler(Consumer<Throwable>) akan membantu Anda dengan ini. Jika ini adalah solusi yang tepat untuk Anda, Anda dapat menangkap semua kesalahan yang dikirim ke 
RxJavaPlugins.onError dan menanganinya sesuai keinginan Anda. Solusi ini bisa sangat rumit - ingat bahwa 
RxJavaPlugins.onError menerima kesalahan dari semua aliran 
RxJava dalam aplikasi.
Jika Anda secara manual membuat 
Observable Anda, Anda dapat memanggil 
emitter.tryOnError() alih-alih 
emitter.tryOnError() . Metode ini melaporkan kesalahan hanya jika aliran tidak dihentikan dan memiliki pelanggan. Ingat bahwa metode ini eksperimental.
Moral dari artikel ini adalah Anda tidak dapat memastikan bahwa tidak ada kesalahan ketika bekerja dengan RxJava jika Anda hanya menerapkan 
onError di pelanggan. Anda harus mengetahui situasi di mana kesalahan mungkin tidak tersedia untuk pelanggan, dan pastikan bahwa situasi ini ditangani.