Rxjava est une implémentation Java VM d'extensions réactives: une bibliothèque pour composer des programmes asynchrones et basés sur des événements en utilisant des séquences observables.
Il étend le modèle d'observateur pour prendre en charge les séquences de données / événements et ajoute des opérateurs qui vous permettent de composer des séquences de manière déclarative tout en abstraction de préoccupations concernant des choses comme le threadage de bas niveau, la synchronisation, les structures de données de sécurité et de filetage et simultanées.
En savoir plus sur Rxjava en général sur la maison wiki.
Veuillez lire ce qui est différent en 3.0 pour plus de détails sur les modifications et les informations de migration lors de la mise à niveau de 2.x.
La version 2.x est fin de vie au 28 février 2021 . Aucun autre développement, support, maintenance, RP et mises à jour ne se produiront. Le Javadoc de la toute dernière version, 2.2.21 , restera accessible.
La version 1.x est fin de vie au 31 mars 2018 . Aucun autre développement, support, maintenance, RP et mises à jour ne se produiront. Le Javadoc de la toute dernière version, 1.3.8 , restera accessible.
La première étape consiste à inclure Rxjava 3 dans votre projet, par exemple, en tant que dépendance de Gradle Compile:
implementation " io.reactivex.rxjava3:rxjava:3.x.y "
(Veuillez remplacer x
et y
par les derniers numéros de version :)
La seconde consiste à écrire le programme 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 );
}
}
Notez que les composants Rxjava 3 vivent désormais sous io.reactivex.rxjava3
et les classes de base et les interfaces vivent sous io.reactivex.rxjava3.core
.
Rxjava 3 propose plusieurs classes de base sur lesquelles vous pouvez découvrir les opérateurs:
io.reactivex.rxjava3.core.Flowable
: 0..N couleio.reactivex.rxjava3.core.Observable
: 0..n coulées, pas de contre-pression,io.reactivex.rxjava3.core.Single
: un flux de 1 élément exactement ou une erreur,io.reactivex.rxjava3.core.Completable
: un flux sans éléments mais seulement un signal d'achèvement ou d'erreur,io.reactivex.rxjava3.core.Maybe
: un flux sans éléments, exactement un élément ou une erreur.Les flux de données dans RXJAVA sont constitués d'une source, de zéro ou plus d'étapes intermédiaires suivis d'une étape de consommateur ou de combinateur de données (où l'étape est responsable de consommer le flux de données par certains moyens):
source . operator1 (). operator2 (). operator3 (). subscribe ( consumer );
source . flatMap ( value -> source . operator1 (). operator2 (). operator3 ());
Ici, si nous nous imaginons sur operator2
, regarder vers la gauche vers la source s'appelle le amont . Regarder vers la droite vers l'abonné / le consommateur s'appelle The en aval . Ceci est souvent plus apparent lorsque chaque élément est écrit sur une ligne séparée:
source
. operator1 ()
. operator2 ()
. operator3 ()
. subscribe ( consumer )
Dans la documentation de Rxjava, les émissions , les émissions , l'élément , l'événement , le signal , les données et le message sont considérés comme des synonymes et représentent l'objet voyageant le long de la flux de données.
Lorsque le flux de données passe par des étapes asynchrones, chaque étape peut effectuer des choses différentes avec une vitesse différente. Pour éviter de submerger de telles étapes, qui se manifesteraient généralement comme une utilisation accrue de la mémoire en raison de la tampon temporaire ou du besoin de sauter / supprimer des données, la soi-disant contre la contre-pression est appliquée, qui est une forme de contrôle de flux où les étapes peuvent exprimer le nombre d'éléments sont-ils prêts à traiter. Cela permet de contraindre l'utilisation de la mémoire des flux de données dans des situations où il n'y a généralement aucun moyen pour une étape de savoir combien d'éléments l'upstream lui enverra.
Dans Rxjava, la classe Flowable
dédiée est désignée pour prendre en charge la contre-pression et Observable
est dédiée aux opérations non backpresurées (séquences courtes, interactions GUI, etc.). Les autres types, Single
, Maybe
et Completable
ne prennent pas en charge la contre-pression non plus; Il y a toujours de la place pour stocker temporairement un article.
La préparation des flux de données en appliquant divers opérateurs intermédiaires se produit dans le temps d'assemblage dit:
Flowable < Integer > flow = Flowable . range ( 1 , 5 )
. map ( v -> v * v )
. filter ( v -> v % 3 == 0 )
;
À ce stade, les données ne coulent pas encore et aucun effet secondaire ne se produit.
Il s'agit d'un état temporaire lorsque subscribe()
est appelé sur un flux qui établit la chaîne d'étapes de traitement en interne:
flow . subscribe ( System . out :: println )
C'est à ce moment que les effets secondaires d'abonnement sont déclenchés (voir doOnSubscribe
). Certaines sources bloquent ou commencent à émettre des articles immédiatement dans cet état.
C'est l'état lorsque les flux émettent activement des éléments, des erreurs ou des signaux d'achèvement:
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 );
En pratique, c'est lorsque le corps de l'exemple donné ci-dessus s'exécute.
L'un des cas d'utilisation courants pour Rxjava est d'exécuter un calcul, une demande de réseau sur un thread d'arrière-plan et afficher les résultats (ou l'erreur) sur le thread d'interface utilisateur:
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
Ce style de méthodes de chaînage est appelé API couramment qui ressemble au modèle du constructeur . Cependant, les types réactifs de Rxjava sont immuables; Chacun des appels de méthode renvoie un nouveau Flowable
avec un comportement ajouté. Pour illustrer, l'exemple peut être réécrit comme suit:
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 );
En règle générale, vous pouvez déplacer des calculs ou bloquer IO vers un autre thread via subscribeOn
. Une fois que les données sont prêtes, vous pouvez vous assurer qu'elles sont traitées au premier plan ou un fil d'interface graphique via observeOn
.
Les opérateurs RXJAVA ne fonctionnent pas directement avec Thread
ou les services ExecutorService
, mais avec les soi-disant Scheduler
qui abstraitent les sources de concurrence derrière une API uniforme. RXJAVA 3 Fonctionne plusieurs planificateurs standard accessibles via Schedulers
de classeurs.
Schedulers.computation()
: Exécutez des travaux à forte intensité de calcul sur un nombre fixe de threads dédiés en arrière-plan. La plupart des opérateurs asynchrones utilisent cela comme Scheduler
par défaut.Schedulers.io()
: Exécutez des opérations de type E / O sur un ensemble de threads changeant dynamiquement.Schedulers.single()
: Exécutez des travaux sur un seul thread d'une manière séquentielle et FIFO.Schedulers.trampoline()
: Exécutez le travail de manière séquentielle et FIFO dans l'un des fils participants, généralement à des fins de test. Ceux-ci sont disponibles sur toutes les plates-formes JVM, mais certaines plates-formes spécifiques, telles que Android, ont leur propre Scheduler
typique défini: AndroidSchedulers.mainThread()
, SwingScheduler.instance()
ou JavaFXScheduler.platform()
.
De plus, il existe une option pour envelopper un Executor
existant (et ses sous-types tels que ExecutorService
) dans un Scheduler
via Schedulers.from(Executor)
. Cela peut être utilisé, par exemple, pour avoir un pool de threads plus grand mais toujours fixe (contrairement computation()
et io()
respectivement).
Le Thread.sleep(2000);
À la fin, ce n'est pas un accident. Dans Rxjava, le Scheduler
par défaut s'exécute sur les threads de démon, ce qui signifie qu'une fois que le thread principal Java sera sorti, ils sont tous arrêtés et que les calculs d'arrière-plan peuvent ne jamais se produire. Dormir pendant un certain temps dans cet exemple de situations vous permet de voir la sortie du flux sur la console avec le temps à perdre.
Les flux de Rxjava sont de nature séquentielle divisé en étapes de traitement qui peuvent s'exécuter simultanément les uns avec les autres:
Flowable . range ( 1 , 10 )
. observeOn ( Schedulers . computation ())
. map ( v -> v * v )
. blockingSubscribe ( System . out :: println );
Cet exemple de flux est en train de fixer les nombres de 1 à 10 sur le Scheduler
de calcul et consomme les résultats sur le thread "principal" (plus précisément, le thread de l'appelant de blockingSubscribe
). Cependant, le Lambda v -> v * v
ne fonctionne pas en parallèle pour ce flux; Il reçoit les valeurs 1 à 10 sur le même thread de calcul l'une après l'autre.
Le traitement des nombres 1 à 10 en parallèle est un peu plus impliqué:
Flowable . range ( 1 , 10 )
. flatMap ( v ->
Flowable . just ( v )
. subscribeOn ( Schedulers . computation ())
. map ( w -> w * w )
)
. blockingSubscribe ( System . out :: println );
Pratiquement, le parallélisme dans Rxjava signifie exécuter des flux indépendants et fusion de leurs résultats en un seul flux. L'opérateur flatMap
le fait en mappant d'abord chaque numéro de 1 à 10 dans son propre Flowable
individuel, les exécute et fusionne les carrés calculés.
Notez, cependant, que flatMap
ne garantit aucune commande et que les éléments des flux intérieurs peuvent finir par être entrelacés. Il existe d'autres opérateurs:
concatMap
qui mappe et exécute un flux intérieur à la fois etconcatMapEager
qui exécute tous les flux intérieurs "immédiatement", mais le flux de sortie sera dans l'ordre, ces flux intérieurs ont été créés. Alternativement, l'opérateur Flowable.parallel()
et le type ParallelFlowable
aident à obtenir le même modèle de traitement parallèle:
Flowable . range ( 1 , 10 )
. parallel ()
. runOn ( Schedulers . computation ())
. map ( v -> v * v )
. sequential ()
. blockingSubscribe ( System . out :: println );
flatMap
est un opérateur puissant et aide dans de nombreuses situations. Par exemple, étant donné un service qui renvoie un Flowable
, nous aimerions appeler un autre service avec des valeurs émises par le premier service:
Flowable < Inventory > inventorySource = warehouse . getInventoryAsync ();
inventorySource
. flatMap ( inventoryItem -> erp . getDemandAsync ( inventoryItem . getId ())
. map ( demand -> "Item " + inventoryItem . getName () + " has demand " + demand ))
. subscribe ( System . out :: println );
Parfois, lorsqu'un élément est devenu disponible, on aimerait effectuer des calculs dépendants. Ceci est parfois appelé la continuation et, selon ce qui devrait se produire et les types impliqués, peut impliquer divers opérateurs à accomplir.
Le scénario le plus typique consiste à donner une valeur, à invoquer un autre service, à attendre et à poursuivre son résultat:
service . apiCall ()
. flatMap ( value -> service . anotherApiCall ( value ))
. flatMap ( next -> service . finalCall ( next ))
Il est souvent le cas également que les séquences ultérieures nécessiteraient des valeurs des mappages antérieurs. Cela peut être réalisé en déplaçant le flatMap
extérieur dans les parties intérieures de la flatMap
précédente par exemple:
service . apiCall ()
. flatMap ( value ->
service . anotherApiCall ( value )
. flatMap ( next -> service . finalCallBoth ( value , next ))
)
Ici, la value
d'origine sera disponible à l'intérieur du flatMap
intérieur, gracieuseté de la capture variable de Lambda.
Dans d'autres scénarios, le (s) résultat de la première source / flux de données n'est pas pertinent et on souhaite continuer avec une autre source quasi indépendante. Ici, flatMap
fonctionne également:
Observable continued = sourceObservable . flatMapSingle ( ignored -> someSingleSource )
continued . map ( v -> v . toString ())
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Cependant, la continuation dans ce cas reste Observable
au lieu du Single
probablement plus approprié. (Ceci est compréhensible car dans le point de vue de flatMapSingle
, sourceObservable
est une source multi-valeurs et donc le mappage peut également entraîner des valeurs multiples).
Souvent, bien qu'il y ait un moyen qui soit un peu plus expressif (et également plus bas) en utilisant Completable
comme médiateur et son opérateur andThen
reprendre avec autre chose:
sourceObservable
. ignoreElements () // returns Completable
. andThen ( someSingleSource )
. map ( v -> v . toString ())
La seule dépendance entre le sourceObservable
et le someSingleSource
est que le premier devrait se terminer normalement pour que les seconds soient consommés.
Parfois, il existe une dépendance implicite des données entre la séquence précédente et la nouvelle séquence qui, pour une raison quelconque, ne circulait pas à travers les "canaux réguliers". On serait enclin à rédiger les continuations que suit:
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . just ( count . get ()))
. subscribe ( System . out :: println );
Malheureusement, cela imprime 0
parce que Single.just(count.get())
est évalué au moment de l'assemblage lorsque le flux de données n'a même pas encore fonctionné. Nous avons besoin de quelque chose qui remet l'évaluation de cette Single
source jusqu'à la fin de la source principale:
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . defer (() -> Single . just ( count . get ())))
. subscribe ( System . out :: println );
ou
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . fromCallable (() -> count . get ()))
. subscribe ( System . out :: println );
Parfois, une source ou un service renvoie un type différent de l'écoulement qui est censé fonctionner avec. Par exemple, dans l'exemple d'inventaire ci-dessus, getDemandAsync
pourrait renvoyer un Single<DemandRecord>
. Si l'exemple de code est resté inchangé, cela entraînera une erreur de compilation (cependant, souvent avec un message d'erreur trompeur sur le manque de surcharge).
Dans de telles situations, il existe généralement deux options pour corriger la transformation: 1) Convertir au type souhaité ou 2) trouver et utiliser une surcharge de l'opérateur spécifique prenant en charge le type différent.
Chaque classe de base réactive propose des opérateurs qui peuvent effectuer de telles conversions, y compris les conversions du protocole, pour correspondre à un autre type. La matrice suivante montre les options de conversion disponibles:
Fluide | Observable | Célibataire | Peut être | Réalisable | |
---|---|---|---|---|---|
Fluide | toObservable | first , firstOrError , single , singleOrError , last , lastOrError 1 | firstElement , singleElement , lastElement | ignoreElements | |
Observable | toFlowable 2 | first , firstOrError , single , singleOrError , last , lastOrError 1 | firstElement , singleElement , lastElement | ignoreElements | |
Célibataire | toFlowable 3 | toObservable | toMaybe | ignoreElement | |
Peut être | toFlowable 3 | toObservable | toSingle | ignoreElement | |
Réalisable | toFlowable | toObservable | toSingle | toMaybe |
1 : Lors de la transformation d'une source multi-valeurs en une source à valeur unique, il faut décider lequel des nombreuses valeurs de source devrait être considéré comme le résultat.
2 : Transformer un Observable
en Flowable
nécessite une décision supplémentaire: que faire avec le flux potentiel sans contrainte de la source Observable
? Il existe plusieurs stratégies disponibles (telles que la mise en mémoire tampon, la suppression, le maintien des derniers) via le paramètre BackpressureStrategy
ou via des opérateurs Flowable
standard tels que onBackpressureBuffer
, onBackpressureDrop
, onBackpressureLatest
qui permettent également une personnalisation supplémentaire du comportement de contre-pression.
3 : Lorsqu'il n'y a que (au plus) un élément source, il n'y a pas de problème avec la contre-pression car il peut être toujours stocké jusqu'à ce que le montant en aval soit prêt à consommer.
De nombreux opérateurs fréquemment utilisés ont des surcharges qui peuvent traiter les autres types. Ceux-ci sont généralement nommés avec le suffixe du type cible:
Opérateur | Surcharge |
---|---|
flatMap | flatMapSingle , flatMapMaybe , flatMapCompletable , flatMapIterable |
concatMap | concatMapSingle concatMapMaybe concatMapCompletable concatMapIterable |
switchMap | switchMapSingle , switchMapMaybe , switchMapCompletable |
La raison pour laquelle ces opérateurs ont un suffixe au lieu d'avoir simplement le même nom avec une signature différente est l'effacement de type. Java ne considère pas les signatures telles que operator(Function<T, Single<R>>)
et operator(Function<T, Maybe<R>>)
différent (contrairement à C #) et en raison de l'effacement, les deux operator
finiraient par comme méthodes en double avec la même signature.
Nommer dans la programmation est l'une des choses les plus difficiles, car les noms ne devraient pas être longs, expressifs, capturés et facilement mémorables. Malheureusement, la langue cible (et les conventions préexistantes) peuvent ne pas donner trop d'aide à cet égard (mots clés inutilisables, effacement de type, ambiguïtés de type, etc.).
Dans le RX.net d'origine, l'opérateur qui émet un seul élément puis termine est appelé Return(T)
. Étant donné que la convention Java doit demander à une lettre minuscule de démarrer un nom de méthode, cela aurait été return(T)
qui est un mot-clé en Java et donc non disponible. Par conséquent, Rxjava a choisi de nommer cet opérateur just(T)
. La même limitation existe pour le Switch
de l'opérateur, qui devait être nommé switchOnNext
. Un autre exemple est Catch
qui a été nommé onErrorResumeNext
.
De nombreux opérateurs qui s'attendent à ce que l'utilisateur fournisse une fonction renvoyant un type réactif ne peut pas être surchargé car l'effacement du type autour d'une Function<T, X>
transforme ces signatures de méthode en doublons. Rxjava a choisi de nommer ces opérateurs en ajoutant le type de suffixe également:
Flowable < R > flatMap ( Function <? super T , ? extends Publisher <? extends R >> mapper )
Flowable < R > flatMapMaybe ( Function <? super T , ? extends MaybeSource <? extends R >> mapper )
Même si certains opérateurs n'ont aucun problème à l'effacement de type, leur signature peut devenir ambiguë, surtout si l'on utilise Java 8 et Lambdas. Par exemple, il existe plusieurs surcharges de concatWith
avec les différents autres types de base réactifs comme arguments (pour fournir des avantages de commodité et de performance dans l'implémentation sous-jacente):
Flowable < T > concatWith ( Publisher <? extends T > other );
Flowable < T > concatWith ( SingleSource <? extends T > other );
Publisher
et SingleSource
apparaissent comme des interfaces fonctionnelles (types avec une méthode abstraite) et peuvent encourager les utilisateurs à essayer de fournir une expression de lambda:
someSource . concatWith ( s -> Single . just ( 2 ))
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Malheureusement, cette approche ne fonctionne pas et l'exemple n'imprime pas du tout 2
. En fait, depuis la version 2.1.10, il ne compile même pas car au moins 4 concatWith
des surcharges existent et le compilateur trouve le code ci-dessus ambigu.
L'utilisateur dans de telles situations voulait probablement reporter un peu de calcul jusqu'à ce que la someSource
soit terminée, donc le bon opérateur sans ambiguïté aurait dû être defer
:
someSource . concatWith ( Single . defer (() -> Single . just ( 2 )))
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Parfois, un suffixe est ajouté pour éviter les ambiguïtés logiques qui peuvent se compiler mais produire le mauvais type dans un flux:
Flowable < T > merge ( Publisher <? extends Publisher <? extends T >> sources );
Flowable < T > mergeArray ( Publisher <? extends T >... sources );
Cela peut également devenir ambigu lorsque les types d'interface fonctionnels s'impliquent à mesure que l'argument de type T
.
Les flux de données peuvent échouer, à quel point l'erreur est émise aux consommateurs. Parfois, cependant, plusieurs sources peuvent échouer à quel point il y a un choix, qu'il s'agisse de tous ou non de terminer ou d'échouer. Pour indiquer cette opportunité, de nombreux noms d'opérateurs sont suffixés avec les mots DelayError
(tandis que d'autres présentent un drapeau booléen delayError
ou delayErrors
dans l'une de leurs surcharges):
Flowable < T > concat ( Publisher <? extends Publisher <? extends T >> sources );
Flowable < T > concatDelayError ( Publisher <? extends Publisher <? extends T >> sources );
Bien sûr, les suffixes de divers types peuvent apparaître ensemble:
Flowable < T > concatArrayEagerDelayError ( Publisher <? extends T >... sources );
Les classes de base peuvent être considérées comme lourdes en raison du nombre de méthodes statiques et d'instance sur eux. La conception de Rxjava 3 a été fortement influencée par la spécification des flux réactives, par conséquent, la bibliothèque dispose d'une classe et d'une interface par chaque type réactif:
Taper | Classe | Interface | Consommateur |
---|---|---|---|
0..N | Flowable | Publisher 1 | Subscriber |
0..N illimité | Observable | ObservableSource 2 | Observer |
1 élément ou erreur | Single | SingleSource | SingleObserver |
0..1 élément ou erreur | Maybe | MaybeSource | MaybeObserver |
0 élément ou erreur | Completable | CompletableSource | CompletableObserver |
1 L' org.reactivestreams.Publisher
fait partie de la bibliothèque de flux réactives externes. Il s'agit du type principal pour interagir avec d'autres bibliothèques réactives via un mécanisme standardisé régi par la spécification des flux réactifs.
2 La convention de dénomination de l'interface était d'ajouter Source
au nom de la classe semi-traditionnelle. Il n'y a pas FlowableSource
puisque Publisher
est fourni par la bibliothèque des flux réactives (et le sous-typage qu'il n'aurait pas aidé à l'interopération non plus). Ces interfaces ne sont cependant pas standard dans le sens de la spécification des flux réactives et sont actuellement spécifiques à Rxjava.
Par défaut, Rxjava lui-même ne nécessite aucun paramètre Proguard / R8 et devrait fonctionner sans problèmes. Malheureusement, la dépendance réactive des flux depuis la version 1.0.3 a intégré des fichiers de classe Java 9 dans son pot qui peuvent provoquer des avertissements avec le progrès simple:
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
Il est recommandé de mettre en place la saisie suivante -dontwarn
dans le fichier proguard-ruleset
de l'application:
-dontwarn java.util.concurrent.Flow*
Pour R8, le JAR RXJAVA comprend la META-INF/proguard/rxjava3.pro
avec la même clause de non-avertissement et devrait s'appliquer automatiquement.
Pour plus de détails, consultez le wiki.
La version 3.x est en développement. BugFixes sera appliquée aux branches 2.x et 3.x, mais de nouvelles fonctionnalités ne seront ajoutées qu'à 3.x.
Les incréments de 3.x mineurs (tels que 3.1, 3.2, etc.) se produiront lorsque de nouvelles fonctionnalités non triviales sont ajoutées ou que des améliorations ou des corrections de bogues se produisent qui peuvent avoir des changements de comportement qui peuvent affecter certains cas de bord (comme la dépendance à l'égard du comportement résultant de un bug). Un exemple d'amélioration qui classerait comme cela ajoute une prise en charge réactive de la backpresure à un opérateur qui ne le soutenait pas auparavant. Cela devrait être en arrière compatible mais se comporte différemment.
Les incréments de patch 3.xy (tels que 3.0.0 -> 3.0.1, 3.3.1 -> 3.3.2, etc.) se produiront pour les corrections de bogues et les fonctionnalités triviales (comme l'ajout d'une surcharge de méthode). De nouvelles fonctionnalités marquées d'une annotation @Beta
ou @Experimental
peuvent également être ajoutées dans les versions de patch pour permettre une exploration rapide et une itération de nouvelles fonctionnalités instables.
Les API marquées de l'annotation @Beta
au niveau de la classe ou de la méthode sont susceptibles de changer. Ils peuvent être modifiés de quelque manière que ce soit, ou même supprimés, à tout moment. Si votre code est une bibliothèque elle-même (c'est-à-dire qu'elle est utilisée sur le chemin de classe des utilisateurs hors de votre contrôle), vous ne devez pas utiliser les API bêta, sauf si vous les reconditionnez (par exemple en utilisant un proguard, un ombrage, etc.).
Les API marquées de l'annotation @Experimental
au niveau de la classe ou de la méthode changeront presque certainement. Ils peuvent être modifiés de quelque manière que ce soit, ou même supprimés, à tout moment. Vous ne devez pas utiliser ou compter sur eux dans un code de production. Ils doivent permettre des tests et des commentaires larges.
Les API marquées de l'annotation @Deprecated
au niveau de la classe ou de la méthode resteront prises en charge jusqu'à la prochaine version majeure, mais il est recommandé de cesser de les utiliser.
Tout le code à l'intérieur du io.reactivex.rxjava3.internal.*
Les packages sont considérés comme une API privée et ne doivent pas du tout être invoqués. Il peut changer à tout moment.
http://reactivex.io/RxJava/3.x/javadoc/3.xy/
Les binaires et les informations de dépendance pour Maven, Ivy, Gradle et autres se trouvent sur http://search.maven.org.
Exemple pour Gradle:
implementation ' io.reactivex.rxjava3:rxjava:x.y.z '
Et pour Maven:
< dependency >
< groupId >io.reactivex.rxjava3</ groupId >
< artifactId >rxjava</ artifactId >
< version >x.y.z</ version >
</ dependency >
Et pour Ivy:
< dependency org = " io.reactivex.rxjava3 " name = " rxjava " rev = " x.y.z " />
Les instantanés après le 1er mai 2021 sont disponibles via 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 '
}
Les instantanés Javadoc sont disponibles sur http://reactivex.io/rxjava/3.x/javadoc/snapshot
Pour construire:
$ git clone [email protected]:ReactiveX/RxJava.git
$ cd RxJava/
$ ./gradlew build
De plus amples détails sur le bâtiment peuvent être trouvés sur la page de démarrage du wiki.
Pour les bogues, les questions et les discussions, veuillez utiliser les problèmes de 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.