
Cukup sering perlu untuk membuat permintaan berulang ke jaringan, misalnya, ketika pengguna tidak memiliki Internet dan ingin menerima data dari Internet. Akan lebih baik untuk melemparkan kembali permintaan saat itu muncul. Merupakan praktik yang baik untuk menunjukkan kepada pengguna UI tertentu yang akan menjelaskan kepadanya apa yang terjadi dan memungkinkan permintaan untuk dilemparkan lagi. Menambahkan logika seperti itu bisa sangat menyakitkan, terutama ketika kita memiliki sejumlah besar kelas ViewModel. Tentu saja, Anda dapat menerapkan logika kueri ulang di setiap kelas ViewModel, tetapi ini tidak nyaman dan ada kemungkinan besar kesalahan.
Apakah ada cara untuk melakukan pemrosesan ini hanya sekali?
Untungnya, RxJava2 dan Retrofit2 memungkinkan ini.
Sudah ada beberapa solusi di Stackoverflow:
1. Membuat CallAdapterFactory Anda sendiri (info lebih lanjut di
sini )
2. Ulangi rantai menggunakan PublishSubject (info lebih lanjut di
sini )
Solusi pertama menggunakan RxJava1, sudah usang dan juga hanya mengulangi rantai beberapa kali, tanpa bereaksi terhadap terjadinya peristiwa tersebut. Solusi kedua baik, tetapi kita perlu menggunakan coba lagi ketika operator di setiap rantai. Jadi, saya menggabungkan dua solusi menjadi satu.
Implementasi
Mari kita buat proyek sederhana. Tempatkan dua tab di layar utama. Masing-masing menampilkan teks yang akan menunjukkan berapa banyak elemen yang dimuat oleh API. Jika kesalahan terjadi selama eksekusi, kami menampilkan SnackBar dengan tombol Coba Lagi.

Kami mendefinisikan kelas-kelas dasar seperti BaseActivity, BaseFragment, BaseViewModel, mereka diperlukan untuk mengimplementasikan logika pengulangan permintaan di satu tempat dan menghindari duplikasi kode ini. Buat dua fragmen yang akan memperpanjang BaseFragment. Setiap fragmen yang ditempatkan memiliki ViewModel sendiri dan secara independen membuat permintaan ke API. Saya membuat cuplikan ini untuk menunjukkan bahwa jika terjadi kesalahan, setiap permintaan akan diulang. Selanjutnya, buat pabrik RxRetryCallAdapterFactory yang memperluas CallAdapter.Factory. Setelah itu, buat instance dari RxJava2CallAdapterFactory. Kami membutuhkan instance ini untuk mengakses RxJava2CallAdapter, karena kami tidak ingin menduplikasi kode yang sudah ada di pustaka Retrofit. Selain itu, mari kita buat metode statis yang akan mengembalikan instance pabrik kami. Contoh kode di bawah ini:
class RxRetryCallAdapterFactory : CallAdapter.Factory() { companion object { fun create() : CallAdapter.Factory = RxRetryCallAdapterFactory() } private val originalFactory = RxJava2CallAdapterFactory.create() override fun get(returnType : Type, annotations : Array<Annotation>, retrofit : Retrofit) : CallAdapter<*, *>? { val adapter = originalFactory.get(returnType, annotations, retrofit) ?: return null return RxRetryCallAdapter(adapter) } }
Selanjutnya, buat RxRetryCallAdapter yang mengimplementasikan antarmuka CallAdapter dan kita perlu meneruskan instance CallAdapter ke konstruktor. Bahkan, itu harus menjadi turunan dari RxJava2CallAdapter, yang mengembalikan pabrik asli.
Selanjutnya, kita perlu menerapkan hal-hal berikut:
- retryWhen pernyataan yang digunakan untuk mengimplementasikan fungsionalitas pengulangan
- pernyataan doOnError () yang menangani kesalahan. Ini digunakan untuk mengirim siaran yang diproses di BaseActivity dan menunjukkan SnackBar kepada pengguna.
- PublishSubject digunakan sebagai pemicu acara yang menandatangani ulang rantai.
- operator observOn (Schedulers.io ()) yang harus diterapkan ke PublishSubject (jika baris ini tidak ditambahkan, berlangganan akan terjadi di utas utama dan kami akan mendapatkan NetworkOnMainThreadException
- Kami mengubah PublishSubject menjadi Flowable dan mengatur BackpressureStrategy.LATEST, karena kami hanya membutuhkan kesalahan terakhir
Catatan: Untuk menyediakan PublishSubject, saya membuat kelas singleton sederhana yang menyediakan semua dependensi singleton dalam proyek. Dalam proyek nyata, Anda cenderung menggunakan kerangka kerja injeksi ketergantungan seperti Dagger2
class RxRetryCallAdapter<R>(private val originalAdapter : CallAdapter<R, *>) : CallAdapter<R, Any> { override fun adapt(call : Call<R>) : Any { val adaptedValue = originalAdapter.adapt(call) return when (adaptedValue) { is Completable -> { adaptedValue.doOnError(this::sendBroadcast) .retryWhen { AppProvider.provideRetrySubject().toFlowable(BackpressureStrategy.LATEST) .observeOn(Schedulers.io()) } } is Single<*> -> { adaptedValue.doOnError(this::sendBroadcast) .retryWhen { AppProvider.provideRetrySubject().toFlowable(BackpressureStrategy.LATEST) .observeOn(Schedulers.io()) } }
Ketika pengguna mengklik tombol Coba lagi, kami memanggil Subtitle PublishSubtext. Setelah itu, kami berlangganan kembali ke rx chain.
Pengujian
Matikan Internet dan jalankan aplikasi. Jumlah item yang dimuat adalah nol pada setiap tab dan SnackBar menampilkan kesalahan. Nyalakan Internet dan klik Coba Adain. Setelah beberapa detik, jumlah item yang dimuat berubah pada masing-masing tab.

Jika ada yang membutuhkannya, maka kode sumbernya ada
di sini