RXJAVA adalah implementasi Java VM dari ekstensi reaktif: perpustakaan untuk menyusun program asinkron dan berbasis peristiwa dengan menggunakan urutan yang dapat diamati.
Ini memperluas pola pengamat untuk mendukung urutan data/peristiwa dan menambahkan operator yang memungkinkan Anda untuk menyusun sekuens bersama-sama secara deklaratif sambil mengabstraksi kekhawatiran tentang hal-hal seperti threading tingkat rendah, sinkronisasi, keselamatan utas dan struktur data bersamaan.
Pelajari lebih lanjut tentang RXJava secara umum di rumah wiki.
Harap baca What Different in 3.0 untuk detail tentang perubahan dan informasi migrasi saat meningkatkan dari 2.x.
Versi 2.x adalah akhir kehidupan pada 28 Februari 2021 . Tidak ada pengembangan, dukungan, pemeliharaan, PRS, dan pembaruan lebih lanjut akan terjadi. Javadoc dari versi terakhir, 2.2.21 , akan tetap dapat diakses.
Versi 1.x adalah akhir kehidupan pada 31 Maret 2018 . Tidak ada pengembangan, dukungan, pemeliharaan, PRS, dan pembaruan lebih lanjut akan terjadi. Javadoc dari versi terakhir, 1.3.8 , akan tetap dapat diakses.
Langkah pertama adalah memasukkan RXJava 3 ke dalam proyek Anda, misalnya, sebagai ketergantungan kompilasi lulusan:
implementation " io.reactivex.rxjava3:rxjava:3.x.y "
(Harap ganti x
dan y
dengan nomor versi terbaru :)
Yang kedua adalah menulis program Hello World :
package rxjava . examples ;
import io . reactivex . rxjava3 . core .*;
public class HelloWorld {
public static void main ( String [] args ) {
Flowable . just ( "Hello world" ). subscribe ( System . out :: println );
}
}
Perhatikan bahwa komponen RXJAVA 3 sekarang hidup di bawah io.reactivex.rxjava3
dan kelas dasar dan antarmuka hidup di bawah io.reactivex.rxjava3.core
.
RXJAVA 3 fitur beberapa kelas dasar yang dapat Anda temukan operator di:
io.reactivex.rxjava3.core.Flowable
: 0..n mengalir, mendukung aliran reaktif dan tekanan balikio.reactivex.rxjava3.core.Observable
: 0..n mengalir, tidak ada tekanan balik,io.reactivex.rxjava3.core.Single
: Aliran tepat 1 item atau kesalahan,io.reactivex.rxjava3.core.Completable
.io.reactivex.rxjava3.core.Maybe
: aliran tanpa item, tepatnya satu item atau kesalahan.Dataflows di RXJava terdiri dari sumber, nol atau lebih langkah perantara diikuti oleh konsumen data atau langkah kombinator (di mana langkah bertanggung jawab untuk mengkonsumsi DataFlow dengan beberapa cara):
source . operator1 (). operator2 (). operator3 (). subscribe ( consumer );
source . flatMap ( value -> source . operator1 (). operator2 (). operator3 ());
Di sini, jika kita membayangkan diri kita di operator2
, melihat ke kiri menuju sumber disebut hulu . Melihat ke kanan menuju pelanggan/konsumen disebut hilir . Ini seringkali lebih jelas ketika setiap elemen ditulis pada baris terpisah:
source
. operator1 ()
. operator2 ()
. operator3 ()
. subscribe ( consumer )
Dalam dokumentasi RXJAVA, emisi , memancarkan , item , acara , sinyal , data , dan pesan dianggap sinonim dan mewakili objek yang bepergian di sepanjang Dataflow.
Ketika Dataflow berjalan melalui langkah -langkah asinkron, setiap langkah dapat melakukan hal yang berbeda dengan kecepatan yang berbeda. Untuk menghindari langkah-langkah yang luar biasa, yang biasanya akan memanifestasikan dirinya sebagai peningkatan penggunaan memori karena buffering sementara atau kebutuhan untuk melewatkan/menjatuhkan data, yang disebut tekanan balik diterapkan, yang merupakan bentuk kontrol aliran di mana langkah-langkah tersebut dapat mengekspresikan berapa banyak item item. apakah mereka siap memproses. Hal ini memungkinkan membatasi penggunaan memori dari dataflow dalam situasi di mana umumnya tidak ada cara untuk langkah untuk mengetahui berapa banyak item yang akan dikirim ke hulu.
Di RXJAVA, kelas Flowable
khusus ditetapkan untuk mendukung tekanan balik dan Observable
didedikasikan untuk operasi yang tidak tertekan (urutan pendek, interaksi GUI, dll.). Jenis -jenis lain, Single
, Maybe
dan Completable
tidak mendukung tekanan balik atau seharusnya mereka; Selalu ada ruang untuk menyimpan satu item sementara.
Persiapan Dataflows dengan menerapkan berbagai operator menengah terjadi pada waktu perakitan yang disebut:
Flowable < Integer > flow = Flowable . range ( 1 , 5 )
. map ( v -> v * v )
. filter ( v -> v % 3 == 0 )
;
Pada titik ini, data belum mengalir dan tidak ada efek samping yang terjadi.
Ini adalah keadaan sementara saat subscribe()
dipanggil pada aliran yang menetapkan rantai langkah pemrosesan secara internal:
flow . subscribe ( System . out :: println )
Ini adalah saat efek samping berlangganan dipicu (lihat doOnSubscribe
). Beberapa sumber memblokir atau mulai memancarkan item segera di negara bagian ini.
Ini adalah keadaan ketika aliran secara aktif memancarkan item, kesalahan atau sinyal penyelesaian:
Observable . create ( emitter -> {
while (! emitter . isDisposed ()) {
long time = System . currentTimeMillis ();
emitter . onNext ( time );
if ( time % 2 != 0 ) {
emitter . onError ( new IllegalStateException ( "Odd millisecond!" ));
break ;
}
}
})
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Secara praktis, ini adalah saat tubuh dari contoh yang diberikan di atas dieksekusi.
Salah satu kasus penggunaan umum untuk RXJAVA adalah menjalankan beberapa perhitungan, permintaan jaringan pada utas latar belakang dan menunjukkan hasil (atau kesalahan) pada utas UI:
import io . reactivex . rxjava3 . schedulers . Schedulers ;
Flowable . fromCallable (() -> {
Thread . sleep ( 1000 ); // imitate expensive computation
return "Done" ;
})
. subscribeOn ( Schedulers . io ())
. observeOn ( Schedulers . single ())
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Thread . sleep ( 2000 ); // <--- wait for the flow to finish
Gaya metode rantai ini disebut API fasih yang menyerupai pola pembangun . Namun, tipe reaktif RXJava tidak dapat diubah; Masing -masing metode panggilan mengembalikan Flowable
baru dengan perilaku yang ditambahkan. Untuk mengilustrasikan, contoh dapat ditulis ulang sebagai berikut:
Flowable < String > source = Flowable . fromCallable (() -> {
Thread . sleep ( 1000 ); // imitate expensive computation
return "Done" ;
});
Flowable < String > runBackground = source . subscribeOn ( Schedulers . io ());
Flowable < String > showForeground = runBackground . observeOn ( Schedulers . single ());
showForeground . subscribe ( System . out :: println , Throwable :: printStackTrace );
Thread . sleep ( 2000 );
Biasanya, Anda dapat memindahkan perhitungan atau memblokir IO ke beberapa utas lain melalui subscribeOn
. Setelah data siap, Anda dapat memastikan mereka diproses di latar depan atau utas GUI melalui observeOn
.
Operator RXJAVA tidak bekerja dengan Thread
S atau ExecutorService
secara langsung tetapi dengan apa yang disebut Scheduler
yang abstrak sumber konkurensi di balik API yang seragam. RXJAVA 3 fitur beberapa penjadwal standar yang dapat diakses melalui kelas utilitas Schedulers
.
Schedulers.computation()
: Jalankan pekerjaan intensif komputasi pada sejumlah utas khusus di latar belakang. Sebagian besar operator asinkron menggunakan ini sebagai Scheduler
default mereka.Schedulers.io()
: Jalankan operasi seperti I/O atau pemblokiran pada set utas yang berubah secara dinamis.Schedulers.single()
: Jalankan bekerja pada satu utas secara berurutan dan FIFO.Schedulers.trampoline()
: Jalankan pekerjaan secara berurutan dan FIFO di salah satu utas yang berpartisipasi, biasanya untuk tujuan pengujian. Ini tersedia di semua platform JVM tetapi beberapa platform spesifik, seperti Android, memiliki Scheduler
khas mereka sendiri yang ditentukan: AndroidSchedulers.mainThread()
, SwingScheduler.instance()
atau JavaFXScheduler.platform()
.
Selain itu, ada opsi untuk membungkus Executor
yang ada (dan subtipe seperti ExecutorService
) ke dalam Scheduler
melalui Schedulers.from(Executor)
. Ini dapat digunakan, misalnya, untuk memiliki kumpulan utas yang lebih besar tetapi masih tetap (tidak seperti computation()
dan io()
masing -masing).
Thread.sleep(2000);
Pada akhirnya bukanlah kecelakaan. Di RXJAVA, Scheduler
default berjalan pada utas daemon, yang berarti begitu utas utama Java keluar, mereka semua dihentikan dan perhitungan latar belakang mungkin tidak akan pernah terjadi. Tidur untuk beberapa waktu dalam contoh ini situasi memungkinkan Anda melihat output aliran pada konsol dengan waktu luang.
Aliran dalam rxJava berurutan di alam terpisah menjadi tahap pemrosesan yang dapat berjalan bersamaan satu sama lain:
Flowable . range ( 1 , 10 )
. observeOn ( Schedulers . computation ())
. map ( v -> v * v )
. blockingSubscribe ( System . out :: println );
Contoh ini mengalir kotak angka dari 1 hingga 10 pada Scheduler
perhitungan dan mengkonsumsi hasil pada utas "utama" (lebih tepatnya, utas penelepon dari blockingSubscribe
). Namun, Lambda v -> v * v
tidak berjalan secara paralel untuk aliran ini; Ia menerima nilai 1 hingga 10 pada utas perhitungan yang sama satu demi satu.
Memproses angka 1 hingga 10 secara paralel sedikit lebih terlibat:
Flowable . range ( 1 , 10 )
. flatMap ( v ->
Flowable . just ( v )
. subscribeOn ( Schedulers . computation ())
. map ( w -> w * w )
)
. blockingSubscribe ( System . out :: println );
Secara praktis, paralelisme dalam RXJava berarti menjalankan aliran independen dan menggabungkan hasilnya kembali ke dalam satu aliran. Operator flatMap
melakukan ini dengan memetakan setiap angka dari 1 hingga 10 ke dalam Flowable
masing -masing, menjalankannya dan menggabungkan kotak yang dihitung.
Perhatikan, bagaimanapun, bahwa flatMap
tidak menjamin pesanan apa pun dan item dari aliran dalam mungkin berakhir diselingi. Ada operator alternatif:
concatMap
yang memetakan dan menjalankan satu aliran dalam sekaligusconcatMapEager
yang menjalankan semua aliran batin "sekaligus" tetapi aliran output akan dalam urutan aliran batin itu dibuat. Atau, operator Flowable.parallel()
dan tipe ParallelFlowable
membantu mencapai pola pemrosesan paralel yang sama:
Flowable . range ( 1 , 10 )
. parallel ()
. runOn ( Schedulers . computation ())
. map ( v -> v * v )
. sequential ()
. blockingSubscribe ( System . out :: println );
flatMap
adalah operator yang kuat dan membantu dalam banyak situasi. Misalnya, diberi layanan yang mengembalikan Flowable
, kami ingin menghubungi layanan lain dengan nilai yang dipancarkan oleh layanan pertama:
Flowable < Inventory > inventorySource = warehouse . getInventoryAsync ();
inventorySource
. flatMap ( inventoryItem -> erp . getDemandAsync ( inventoryItem . getId ())
. map ( demand -> "Item " + inventoryItem . getName () + " has demand " + demand ))
. subscribe ( System . out :: println );
Kadang -kadang, ketika suatu item telah tersedia, orang ingin melakukan beberapa perhitungan tergantung di atasnya. Ini kadang -kadang disebut kelanjutan dan, tergantung pada apa yang harus terjadi dan jenis apa yang terlibat, mungkin melibatkan berbagai operator untuk dicapai.
Skenario yang paling khas adalah memberikan nilai, memohon layanan lain, menunggu dan melanjutkan hasilnya:
service . apiCall ()
. flatMap ( value -> service . anotherApiCall ( value ))
. flatMap ( next -> service . finalCall ( next ))
Sering kali juga bahwa urutan nanti akan membutuhkan nilai dari pemetaan sebelumnya. Ini dapat dicapai dengan memindahkan flatMap
luar ke bagian dalam flatMap
sebelumnya misalnya:
service . apiCall ()
. flatMap ( value ->
service . anotherApiCall ( value )
. flatMap ( next -> service . finalCallBoth ( value , next ))
)
Di sini, value
aslinya akan tersedia di dalam flatMap
dalam, milik Lambda Variable Capture.
Dalam skenario lain, hasil dari sumber/dataflow pertama tidak relevan dan orang ingin melanjutkan dengan sumber independen yang mandiri. Di sini, flatMap
juga berfungsi:
Observable continued = sourceObservable . flatMapSingle ( ignored -> someSingleSource )
continued . map ( v -> v . toString ())
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Namun, kelanjutan dalam kasus ini tetap Observable
, bukan Single
yang lebih tepat. (Ini dapat dimengerti karena dari perspektif flatMapSingle
, sourceObservable
adalah sumber multi-bernilai dan dengan demikian pemetaan dapat menghasilkan beberapa nilai juga).
Seringkali meskipun ada cara yang agak lebih ekspresif (dan juga overhead yang lebih rendah) dengan menggunakan Completable
sebagai mediator dan operatornya andThen
melanjutkan dengan sesuatu yang lain:
sourceObservable
. ignoreElements () // returns Completable
. andThen ( someSingleSource )
. map ( v -> v . toString ())
Satu -satunya ketergantungan antara sourceObservable
dan someSingleSource
adalah bahwa yang pertama harus diselesaikan secara normal agar yang terakhir dikonsumsi.
Kadang -kadang, ada ketergantungan data implisit antara urutan sebelumnya dan urutan baru yang, untuk beberapa alasan, tidak mengalir melalui "saluran reguler". Seseorang akan cenderung menulis kelanjutan seperti berikut:
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . just ( count . get ()))
. subscribe ( System . out :: println );
Sayangnya , ini mencetak 0
karena Single.just(count.get())
. Kami membutuhkan sesuatu yang menentang evaluasi sumber Single
ini sampai runtime ketika sumber utama selesai:
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . defer (() -> Single . just ( count . get ())))
. subscribe ( System . out :: println );
atau
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . fromCallable (() -> count . get ()))
. subscribe ( System . out :: println );
Terkadang, sumber atau layanan mengembalikan jenis yang berbeda dari aliran yang seharusnya bekerja dengannya. Misalnya, dalam contoh inventaris di atas, getDemandAsync
dapat mengembalikan satu Single<DemandRecord>
. Jika contoh kode dibiarkan tidak berubah, ini akan menghasilkan kesalahan waktu kompilasi (namun, seringkali dengan pesan kesalahan yang menyesatkan tentang kurangnya kelebihan beban).
Dalam situasi seperti itu, biasanya ada dua opsi untuk memperbaiki transformasi: 1) dikonversi ke tipe yang diinginkan atau 2) menemukan dan menggunakan kelebihan operator spesifik yang mendukung jenis yang berbeda.
Setiap kelas dasar reaktif menampilkan operator yang dapat melakukan konversi seperti itu, termasuk konversi protokol, untuk mencocokkan beberapa jenis lainnya. Matriks berikut menunjukkan opsi konversi yang tersedia:
Bisa mengalir | Tampak | Lajang | Mungkin | Bisa diselesaikan | |
---|---|---|---|---|---|
Bisa mengalir | toObservable | first , firstOrError , single , singleOrError , last , lastOrError 1 | firstElement , singleElement , lastElement | ignoreElements | |
Tampak | toFlowable 2 | first , firstOrError , single , singleOrError , last , lastOrError 1 | firstElement , singleElement , lastElement | ignoreElements | |
Lajang | toFlowable 3 | toObservable | toMaybe | ignoreElement | |
Mungkin | toFlowable 3 | toObservable | toSingle | ignoreElement | |
Bisa diselesaikan | toFlowable | toObservable | toSingle | toMaybe |
1 : Saat mengubah sumber multi-bernilai menjadi sumber bernilai tunggal, seseorang harus memutuskan mana dari banyak nilai sumber yang harus dianggap sebagai hasilnya.
2 : mengubah yang Observable
menjadi Flowable
membutuhkan keputusan tambahan: Apa yang harus dilakukan dengan potensi aliran sumber yang tidak dibatasi Observable
? Ada beberapa strategi yang tersedia (seperti buffering, dropping, menjaga yang terbaru) melalui parameter BackpressureStrategy
atau melalui operator Flowable
standar seperti onBackpressureBuffer
, onBackpressureDrop
, onBackpressureLatest
yang juga memungkinkan penyesuaian lebih lanjut dari perilaku tekanan balik.
3 : Ketika hanya ada (paling banyak) satu item sumber, tidak ada masalah dengan tekanan balik karena dapat selalu disimpan sampai hilir siap dikonsumsi.
Banyak operator yang sering digunakan memiliki kelebihan beban yang dapat menangani jenis lain. Ini biasanya dinamai dengan akhiran jenis target:
Operator | Kelebihan beban |
---|---|
flatMap | flatMapSingle , flatMapMaybe , flatMapCompletable , flatMapIterable |
concatMap | concatMapSingle , concatMapMaybe , concatMapCompletable , concatMapIterable |
switchMap | switchMapSingle , switchMapMaybe , switchMapCompletable |
Alasan operator ini memiliki akhiran alih -alih hanya memiliki nama yang sama dengan tanda tangan yang berbeda adalah tipe penghapusan. Java tidak mempertimbangkan tanda tangan seperti operator(Function<T, Single<R>>)
dan operator(Function<T, Maybe<R>>)
berbeda (tidak seperti c#) dan karena penghapusan, kedua operator
akan berakhir sebagai metode duplikat dengan tanda tangan yang sama.
Penamaan dalam pemrograman adalah salah satu hal tersulit karena nama diharapkan tidak panjang, ekspresif, menangkap dan mudah diingat. Sayangnya, bahasa target (dan konvensi yang sudah ada sebelumnya) mungkin tidak memberikan terlalu banyak bantuan dalam hal ini (kata kunci yang tidak dapat digunakan, jenis penghapusan, jenis ambiguitas, dll.).
Dalam rx.net asli, operator yang memancarkan satu item dan kemudian diselesaikan disebut Return(T)
. Karena Konvensi Java adalah memiliki huruf kecil, mulai nama metode, ini akan return(T)
yang merupakan kata kunci di Java dan karenanya tidak tersedia. Oleh karena itu, RXJava memilih untuk menyebutkan Operator ini just(T)
. Batasan yang sama ada untuk Switch
operator, yang harus dinamai switchOnNext
. Contoh lain adalah Catch
yang dinamai onErrorResumeNext
.
Banyak operator yang mengharapkan pengguna untuk menyediakan beberapa fungsi yang mengembalikan tipe reaktif tidak dapat kelebihan beban karena jenis penghapusan di sekitar Function<T, X>
mengubah tanda tangan metode tersebut menjadi duplikat. RXJAVA memilih untuk menyebutkan operator tersebut dengan menambahkan tipe sebagai akhiran juga:
Flowable < R > flatMap ( Function <? super T , ? extends Publisher <? extends R >> mapper )
Flowable < R > flatMapMaybe ( Function <? super T , ? extends MaybeSource <? extends R >> mapper )
Meskipun operator tertentu tidak memiliki masalah dari penghapusan jenis, tanda tangan mereka mungkin muncul menjadi ambigu, terutama jika seseorang menggunakan Java 8 dan Lambdas. Misalnya, ada beberapa kelebihan concatWith
dengan mengambil berbagai jenis dasar reaktif lainnya sebagai argumen (untuk memberikan manfaat kenyamanan dan kinerja dalam implementasi yang mendasarinya):
Flowable < T > concatWith ( Publisher <? extends T > other );
Flowable < T > concatWith ( SingleSource <? extends T > other );
Baik Publisher
dan SingleSource
muncul sebagai antarmuka fungsional (tipe dengan satu metode abstrak) dan dapat mendorong pengguna untuk mencoba memberikan ekspresi lambda:
someSource . concatWith ( s -> Single . just ( 2 ))
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Sayangnya, pendekatan ini tidak berhasil dan contoh tidak mencetak 2
sama sekali. Bahkan, karena versi 2.1.10, itu bahkan tidak dikompilasi karena setidaknya 4 concatWith
dengan kelebihan beban dan kompiler menemukan kode di atas ambigu.
Pengguna dalam situasi seperti itu mungkin ingin menunda beberapa perhitungan sampai someSource
telah selesai, sehingga operator yang tidak ambigu yang benar seharusnya defer
:
someSource . concatWith ( Single . defer (() -> Single . just ( 2 )))
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Terkadang, akhiran ditambahkan untuk menghindari ambiguitas logis yang dapat dikompilasi tetapi menghasilkan jenis yang salah dalam aliran:
Flowable < T > merge ( Publisher <? extends Publisher <? extends T >> sources );
Flowable < T > mergeArray ( Publisher <? extends T >... sources );
Ini juga bisa menjadi ambigu ketika tipe antarmuka fungsional terlibat sebagai argumen tipe T
.
Dataflows dapat gagal, pada titik mana kesalahan dipancarkan ke konsumen. Namun kadang -kadang, banyak sumber mungkin gagal pada titik mana ada pilihan apakah menunggu semuanya untuk menyelesaikan atau gagal. Untuk menunjukkan peluang ini, banyak nama operator yang sufiks dengan kata -kata DelayError
(sementara yang lain menampilkan bendera Boolean delayError
atau delayErrors
di salah satu kelebihan beban mereka):
Flowable < T > concat ( Publisher <? extends Publisher <? extends T >> sources );
Flowable < T > concatDelayError ( Publisher <? extends Publisher <? extends T >> sources );
Tentu saja, sufiks dari berbagai jenis mungkin muncul bersama:
Flowable < T > concatArrayEagerDelayError ( Publisher <? extends T >... sources );
Kelas dasar dapat dianggap berat karena banyaknya metode statis dan instance pada mereka. Desain RXJAVA 3 sangat dipengaruhi oleh spesifikasi aliran reaktif, oleh karena itu, perpustakaan memiliki kelas dan antarmuka per masing -masing jenis reaktif:
Jenis | Kelas | Antarmuka | Konsumen |
---|---|---|---|
0..n Tangguh kembali | Flowable | Publisher 1 | Subscriber |
0..n tidak terikat | Observable | ObservableSource 2 | Observer |
1 elemen atau kesalahan | Single | SingleSource | SingleObserver |
0..1 Elemen atau Kesalahan | Maybe | MaybeSource | MaybeObserver |
0 Elemen atau Kesalahan | Completable | CompletableSource | CompletableObserver |
1 The org.reactivestreams.Publisher
adalah bagian dari pustaka aliran reaktif eksternal. Ini adalah tipe utama untuk berinteraksi dengan perpustakaan reaktif lainnya melalui mekanisme standar yang diatur oleh spesifikasi aliran reaktif.
2 Konvensi penamaan antarmuka adalah untuk menambahkan Source
ke nama kelas semi-tradisional. Tidak ada FlowableSource
karena Publisher
disediakan oleh Perpustakaan Stream Reaktif (dan subtipe itu tidak akan membantu dengan interoperasi juga). Antarmuka ini, bagaimanapun, bukan standar dalam arti spesifikasi aliran reaktif dan saat ini hanya RXJAVA khusus.
Secara default, RXJava sendiri tidak memerlukan pengaturan Proguard/R8 dan harus bekerja tanpa masalah. Sayangnya, ketergantungan aliran reaktif sejak versi 1.0.3 telah menanamkan file kelas Java 9 dalam toples yang dapat menyebabkan peringatan dengan proguard polos:
Warning: org.reactivestreams.FlowAdapters$FlowPublisherFromReactive: can't find superclass or interface java.util.concurrent.Flow$Publisher
Warning: org.reactivestreams.FlowAdapters$FlowToReactiveProcessor: can't find superclass or interface java.util.concurrent.Flow$Processor
Warning: org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber: can't find superclass or interface java.util.concurrent.Flow$Subscriber
Warning: org.reactivestreams.FlowAdapters$FlowToReactiveSubscription: can't find superclass or interface java.util.concurrent.Flow$Subscription
Warning: org.reactivestreams.FlowAdapters: can't find referenced class java.util.concurrent.Flow$Publisher
Direkomendasikan satu mengatur entri -dontwarn
berikut dalam file proguard-ruleset
aplikasi:
-dontwarn java.util.concurrent.Flow*
Untuk R8, toples RXJAVA termasuk META-INF/proguard/rxjava3.pro
dengan klausa yang sama tanpa peringatan dan harus berlaku secara otomatis.
Untuk perincian lebih lanjut, konsultasikan dengan wiki.
Versi 3.x sedang dalam pengembangan. Perbaikan bug akan diterapkan pada cabang 2.x dan 3.x, tetapi fitur baru hanya akan ditambahkan ke 3.x.
Penambahan minor 3.x (seperti 3.1, 3.2, dll) akan terjadi ketika fungsionalitas baru yang tidak sepele ditambahkan atau peningkatan yang signifikan atau perbaikan bug terjadi yang mungkin memiliki perubahan perilaku yang mungkin mempengaruhi beberapa kasus tepi (seperti ketergantungan pada perilaku yang dihasilkan dari yang dihasilkan dari bug). Contoh peningkatan yang akan mengklasifikasikan karena ini adalah menambahkan dukungan tekanan balik reaktif ke operator yang sebelumnya tidak mendukungnya. Ini harus kompatibel ke belakang tetapi tidak berperilaku berbeda.
Patch 3.xy Peningkatan (seperti 3.0.0 -> 3.0.1, 3.3.1 -> 3.3.2, dll) akan terjadi untuk perbaikan bug dan fungsionalitas sepele (seperti menambahkan metode kelebihan metode). Fungsionalitas baru yang ditandai dengan anotasi @Beta
atau @Experimental
juga dapat ditambahkan dalam rilis patch untuk memungkinkan eksplorasi cepat dan iterasi fungsionalitas baru yang tidak stabil.
API yang ditandai dengan anotasi @Beta
di kelas atau tingkat metode dapat berubah. Mereka dapat dimodifikasi dengan cara apa pun, atau bahkan dihapus, kapan saja. Jika kode Anda adalah perpustakaan itu sendiri (yaitu itu digunakan pada classpath pengguna di luar kendali Anda), Anda tidak boleh menggunakan beta API, kecuali Anda mengemasnya kembali (misalnya menggunakan proguard, naungan, dll).
API yang ditandai dengan anotasi @Experimental
di tingkat kelas atau metode hampir pasti akan berubah. Mereka dapat dimodifikasi dengan cara apa pun, atau bahkan dihapus, kapan saja. Anda tidak boleh menggunakan atau mengandalkannya dalam kode produksi apa pun. Mereka murni untuk memungkinkan pengujian dan umpan balik yang luas.
API yang ditandai dengan anotasi @Deprecated
di tingkat kelas atau metode akan tetap didukung sampai rilis besar berikutnya, tetapi disarankan untuk berhenti menggunakannya.
Semua kode di dalam io.reactivex.rxjava3.internal.*
Paket dianggap sebagai API pribadi dan tidak boleh diandalkan sama sekali. Itu bisa berubah kapan saja.
http://reactivex.io/RxJava/3.x/javadoc/3.xy/
Binari dan informasi ketergantungan untuk Maven, Ivy, Gradle dan lainnya dapat ditemukan di http://search.maven.org.
Contoh untuk lulusan:
implementation ' io.reactivex.rxjava3:rxjava:x.y.z '
Dan untuk Maven:
< dependency >
< groupId >io.reactivex.rxjava3</ groupId >
< artifactId >rxjava</ artifactId >
< version >x.y.z</ version >
</ dependency >
Dan untuk Ivy:
< dependency org = " io.reactivex.rxjava3 " name = " rxjava " rev = " x.y.z " />
Snapshot setelah 1 Mei 2021 tersedia melalui https://oss.sonatype.org/content/repositories/snapshots/io/reactivex/rxjava3/rxjava/
repositories {
maven { url ' https://oss.sonatype.org/content/repositories/snapshots ' }
}
dependencies {
implementation ' io.reactivex.rxjava3:rxjava:3.0.0-SNAPSHOT '
}
Snapshot Javadoc tersedia di http://reactivex.io/rxjava/3.x/javadoc/snapshot
Untuk membangun:
$ git clone [email protected]:ReactiveX/RxJava.git
$ cd RxJava/
$ ./gradlew build
Rincian lebih lanjut tentang bangunan dapat ditemukan di halaman pemula wiki.
Untuk bug, pertanyaan, dan diskusi, silakan gunakan masalah GitHub.
Copyright (c) 2016-present, RxJava Contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.