Pengantar RxKotlin

1. Ikhtisar

Dalam tutorial ini, kita akan meninjau penggunaan Reactive Extensions (Rx) di Kotlin idiomatik menggunakan pustaka RxKotlin.

RxKotlin bukanlah implementasi dari Ekstensi Reaktif, per se. Sebaliknya, ini sebagian besar merupakan kumpulan metode ekstensi. Artinya, RxKotlin menambah pustaka RxJava dengan API yang dirancang dengan mempertimbangkan Kotlin.

Oleh karena itu, kami akan menggunakan konsep dari artikel kami, Pengantar RxJava, serta konsep Flowable yang telah kami sajikan dalam artikel khusus.

2. Pengaturan RxKotlin

Untuk menggunakan RxKotlin dalam proyek Maven kita, kita perlu menambahkan ketergantungan rxkotlin ke pom.xml kita :

 io.reactivex.rxjava2 rxkotlin 2.3.0 

Atau, untuk proyek Gradle, ke build.gradle kami :

implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'

Di sini, kami menggunakan RxKotlin 2.x, yang menargetkan RxJava 2. Proyek yang menggunakan RxJava 1 harus menggunakan RxKotlin 1.x. Konsep yang sama berlaku untuk kedua versi.

Perhatikan bahwa RxKotlin bergantung pada RxJava, tetapi mereka tidak sering memperbarui dependensi ke rilis terbaru. Jadi, kami menyarankan untuk secara eksplisit menyertakan versi RxJava tertentu yang akan kami andalkan, seperti yang dijelaskan dalam artikel RxJava kami.

3. Membuat Observable di RxKotlin

RxKotlin menyertakan sejumlah metode ekstensi untuk membuat objek Observable dan Flowable dari koleksi.

Secara khusus, setiap jenis array memiliki metode toObservable () dan metode toFlowable () :

val observable = listOf(1, 1, 2, 3).toObservable() observable.test().assertValues(1, 1, 2, 3)
val flowable = listOf(1, 1, 2, 3).toFlowable() flowable.buffer(2).test().assertValues(listOf(1, 1), listOf(2, 3))

3.1. S selesai

RxKotlin juga menyediakan beberapa metode untuk membuat instance yang Dapat Diselesaikan . Secara khusus, kita dapat mengonversi fungsi Action s, Callable s, Future s, dan zero-arity menjadi Completable dengan metode ekstensi toCompletable:

var value = 0 val completable = { value = 3 }.toCompletable() assertFalse(completable.test().isCancelled()) assertEquals(3, value)

4. diamati dan Flowable untuk Peta dan Multimap

Saat kita memiliki Observable atau Flowable yang menghasilkan instance Pair , kita bisa mengubahnya menjadi Observable tunggal yang menghasilkan Map:

val list = listOf(Pair("a", 1), Pair("b", 2), Pair("c", 3), Pair("a", 4)) val observable = list.toObservable() val map = observable.toMap() assertEquals(mapOf(Pair("a", 4), Pair("b", 2), Pair("c", 3)), map.blockingGet())

Seperti yang dapat kita lihat pada contoh sebelumnya, toMap menimpa nilai yang dikeluarkan sebelumnya dengan nilai yang lebih baru jika memiliki kunci yang sama.

Jika kami ingin mengakumulasi semua nilai yang terkait dengan kunci ke dalam koleksi, kami menggunakan toMultimap sebagai gantinya:

val list = listOf(Pair("a", 1), Pair("b", 2), Pair("c", 3), Pair("a", 4)) val observable = list.toObservable() val map = observable.toMultimap() assertEquals( mapOf(Pair("a", listOf(1, 4)), Pair("b", listOf(2)), Pair("c", listOf(3))), map.blockingGet())

5. Menggabungkan diamati dan Flowable s

Salah satu nilai jual Rx adalah kemungkinan untuk menggabungkan Observable s dan Flowable s dalam berbagai cara. Memang, RxJava menyediakan sejumlah operator di luar kotak.

Selain itu, RxKotlin menyertakan beberapa metode ekstensi lagi untuk menggabungkan Observable dan sejenisnya.

5.1. Menggabungkan Emisi yang Dapat Diamati

Ketika kita memiliki Observable yang memancarkan Observable lainnya , kita dapat menggunakan salah satu metode ekstensi di RxKotlin untuk menggabungkan bersama nilai yang dipancarkan.

Secara khusus, mergeAll menggabungkan observable dengan flatMap:

val subject = PublishSubject.create
    
     () val observable = subject.mergeAll()
    

Yang mana akan sama dengan:

val observable = subject.flatMap { it }

Hasil Pengamatan akan memancarkan semua nilai sumber Pengamatan dalam urutan yang tidak ditentukan.

Demikian pula, concatAll menggunakan concatMap (nilai dipancarkan dalam urutan yang sama dengan sumber), sedangkan switchLatest menggunakan switchMap (nilai dikeluarkan dari Observable yang terakhir dipancarkan ).

Seperti yang telah kita lihat sejauh ini, semua metode di atas disediakan untuk sumber Flowable juga, dengan semantik yang sama.

5.2. Menggabungkan Completable s , Maybe s, dan Single s

Ketika kita memiliki Observable yang memancarkan instance Completable , Maybe , atau Single , kita bisa menggabungkannya dengan metode mergeAllXs yang sesuai seperti, misalnya, mergeAllMaybes :

val subject = PublishSubject.create
    
     () val observable = subject.mergeAllMaybes() subject.onNext(Maybe.just(1)) subject.onNext(Maybe.just(2)) subject.onNext(Maybe.empty()) subject.onNext(Maybe.error(Exception("error"))) subject.onNext(Maybe.just(3)) observable.test().assertValues(1, 2).assertError(Exception::class.java)
    

5.3. Menggabungkan Iterable s of diamati s

Sebagai gantinya, untuk kumpulan instance Observable atau Flowable , RxKotlin memiliki beberapa operator lain, gabung dan mergeDelayError . Keduanya memiliki efek menggabungkan semua Observable s atau Flowable menjadi satu yang akan memancarkan semua nilai secara berurutan:

val observables = mutableListOf(Observable.just("first", "second")) val observable = observables.merge() observables.add(Observable.just("third", "fourth")) observable.test().assertValues("first", "second", "third", "fourth")

The difference between the two operators — which are directly derived from the same-named operators in RxJava — is their treatment of errors.

The merge method emits errors as soon as they're emitted by the source:

// ... observables.add(Observable.error(Exception("e"))) observables.add(Observable.just("fifth")) // ... observable.test().assertValues("first", "second", "third", "fourth")

Whereas mergeDelayError emits them at the end of the stream:

// ... observables.add(Observable.error(Exception("e"))) observables.add(Observable.just("fifth")) // ... observable.test().assertValues("first", "second", "third", "fourth", "fifth")

6. Handling Values of Different Types

Let's now look at the extension methods in RxKotlin for dealing with values of different types.

These are variants of RxJava methods, that make use of Kotlin's reified generics. In particular, we can:

  • cast emitted values from one type to another, or
  • filter out values that are not of a certain type

So, we could, for example, cast an Observable of Numbers to one of Ints:

val observable = Observable.just(1, 1, 2, 3) observable.cast().test().assertValues(1, 1, 2, 3)

Here, the cast is unnecessary. However, when combining different observables together, we might need it.

With ofType, instead, we can filter out values that aren't of the type we expect:

val observable = Observable.just(1, "and", 2, "and") observable.ofType().test().assertValues(1, 2)

As always, cast and ofType are applicable to both Observables and Flowables.

Furthermore, Maybe supports these methods as well. The Single class, instead, only supports cast.

7. Other Helper Methods

Finally, RxKotlin includes several helper methods. Let's have a quick look.

We can use subscribeBy instead of subscribe – it allows named parameters:

Observable.just(1).subscribeBy(onNext = { println(it) })

Similarly, for blocking subscriptions we can use blockingSubscribeBy.

Additionally, RxKotlin includes some methods that mimic those in RxJava but work around a limitation of Kotlin's type inference.

For example, when using Observable#zip, specifying the zipper doesn't look so great:

Observable.zip(Observable.just(1), Observable.just(2), BiFunction { a, b -> a + b })

So, RxKotlin adds Observables#zip for more idiomatic usage:

Observables.zip(Observable.just(1), Observable.just(2)) { a, b -> a + b }

Notice the final “s” in Observables. Similarly, we have Flowables, Singles, and Maybes.

8. Conclusions

Di artikel ini, kami telah meninjau pustaka RxKotlin secara menyeluruh, yang menambahkan RxJava untuk membuat API-nya terlihat lebih seperti Kotlin idiomatik.

Untuk informasi lebih lanjut, silakan merujuk ke halaman RxKotlin GitHub. Untuk contoh lainnya, kami merekomendasikan pengujian RxKotlin.

Penerapan semua contoh dan cuplikan kode ini dapat ditemukan di proyek GitHub sebagai proyek Maven dan Gradle, jadi semestinya mudah untuk mengimpor dan menjalankan apa adanya.