RXJAVA es una implementación de Java VM de extensiones reactivas: una biblioteca para componer programas asincrónicos y basados en eventos mediante el uso de secuencias observables.
Extiende el patrón del observador para admitir secuencias de datos/eventos y agrega operadores que le permiten componer secuencias juntas declarativamente mientras abstrae preocupaciones sobre cosas como roscado de bajo nivel, sincronización, seguridad de hilos y estructuras de datos concurrentes.
Obtenga más información sobre Rxjava en general en la casa de Wiki.
Lea lo diferente en 3.0 para obtener detalles sobre los cambios y la información de migración al actualizar desde 2.x.
La versión 2.x es finales de la vida a fines del 28 de febrero de 2021 . No se producirán más desarrollo, apoyo, mantenimiento, PRS y actualizaciones. El Javadoc de la última versión, 2.2.21 , permanecerá accesible.
La versión 1.x es a fin de vida al 31 de marzo de 2018 . No se producirán más desarrollo, apoyo, mantenimiento, PRS y actualizaciones. El Javadoc de la última versión, 1.3.8 , permanecerá accesible.
El primer paso es incluir rxjava 3 en su proyecto, por ejemplo, como una dependencia de la compilación de graduación:
implementation " io.reactivex.rxjava3:rxjava:3.x.y "
(Reemplace x
e y
con los últimos números de versión :)
El segundo es escribir el programa 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 );
}
}
Tenga en cuenta que los componentes RXJAVA 3 ahora viven bajo io.reactivex.rxjava3
y las clases e interfaces base viven bajo io.reactivex.rxjava3.core
.
RXJAVA 3 presenta varias clases base en las que puede descubrir operadores:
io.reactivex.rxjava3.core.Flowable
: 0..N fluye, soportando transmisiones reactivas y backpressureio.reactivex.rxjava3.core.Observable
: 0..n fluye, sin backpressure,io.reactivex.rxjava3.core.Single
: un flujo de exactamente 1 elemento o un error,io.reactivex.rxjava3.core.Completable
: un flujo sin elementos pero solo una señal de finalización o error,io.reactivex.rxjava3.core.Maybe
: un flujo sin elementos, exactamente un elemento o un error.Los flujos de datos en rxJava consisten en una fuente, cero o más pasos intermedios seguidos de un paso de consumidor o combinador de datos (donde el paso es responsable de consumir el flujo de datos por algunos medios):
source . operator1 (). operator2 (). operator3 (). subscribe ( consumer );
source . flatMap ( value -> source . operator1 (). operator2 (). operator3 ());
Aquí, si nos imaginamos en operator2
, mirar hacia la izquierda hacia la fuente se llama aguas arriba . Mirar hacia la derecha hacia el suscriptor/consumidor se llama aguas abajo . Esto a menudo es más evidente cuando cada elemento está escrito en una línea separada:
source
. operator1 ()
. operator2 ()
. operator3 ()
. subscribe ( consumer )
En la documentación, emisión , emisión , emisión, elemento , evento , señal , datos y mensajes de Rxjava, se consideran sinónimos y representan el objeto que viaja a lo largo del flujo de datos.
Cuando el flujo de datos se ejecuta a través de pasos asincrónicos, cada paso puede realizar cosas diferentes con una velocidad diferente. Para evitar abrumadores tales pasos, que generalmente se manifestarían a sí mismo como un mayor uso de la memoria debido al almacenamiento en búfer temporal o la necesidad de omitir/soltar datos, se aplica la llamada contrapresión, que es una forma de control de flujo donde los pasos pueden expresar cuántos elementos pueden expresar cuántos elementos ¿Están listos para procesar? Esto permite restringir el uso de la memoria de los flujos de datos en situaciones en las que generalmente no hay forma de que un paso sepa cuántos elementos le enviará el río arriba.
En RXJAVA, la clase Flowable
dedicada está designada para admitir backpressure y Observable
se dedica a las operaciones no compensadas (secuencias cortas, interacciones GUI, etc.). Los otros tipos, Single
, Maybe
y Completable
no admiten backpressure ni deberían; Siempre hay espacio para almacenar un artículo temporalmente.
La preparación de flujos de datos aplicando varios operadores intermedios ocurre en el llamado tiempo de ensamblaje :
Flowable < Integer > flow = Flowable . range ( 1 , 5 )
. map ( v -> v * v )
. filter ( v -> v % 3 == 0 )
;
En este punto, los datos aún no fluyen y no están ocurriendo efectos secundarios.
Este es un estado temporal cuando subscribe()
se llama a un flujo que establece la cadena de pasos de procesamiento internamente:
flow . subscribe ( System . out :: println )
Esto es cuando se activan los efectos secundarios de la suscripción (ver doOnSubscribe
). Algunas fuentes bloquean o comienzan a emitir artículos de inmediato en este estado.
Este es el estado cuando los flujos están emitiendo activamente elementos, errores o señales de finalización:
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 );
Prácticamente, esto es cuando el cuerpo del ejemplo dado se ejecuta.
Uno de los casos de uso comunes para RXJAVA es ejecutar algún cálculo, solicitud de red en un subproceso de fondo y mostrar los resultados (o error) en el hilo de la interfaz de usuario:
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
Este estilo de métodos de encadenamiento se llama API con fluidez que se asemeja al patrón de constructor . Sin embargo, los tipos reactivos de Rxjava son inmutables; Cada una de las llamadas de método devuelve un nuevo Flowable
con comportamiento adicional. Para ilustrar, el ejemplo se puede reescribir de la siguiente manera:
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 );
Por lo general, puede mover cálculos o bloquear IO a algún otro hilo a través subscribeOn
. Una vez que los datos están listos, puede asegurarse de que se procesen en primer plano o en el hilo de la GUI a través de observeOn
.
Los operadores de RXJava no funcionan con Thread
S o ExecutorService
S directamente, sino con los llamados Scheduler
que resumen las fuentes de concurrencia detrás de una API uniforme. RXJAVA 3 presenta varios programadores estándar accesibles a través de la clase de utilidad Schedulers
.
Schedulers.computation()
: ejecute el trabajo intensivo de cálculo en un número fijo de subprocesos dedicados en segundo plano. La mayoría de los operadores asíncronos usan esto como su Scheduler
predeterminado.Schedulers.io()
: ejecute operaciones de bloqueo o bloqueo de I/O en un conjunto de subprocesos que cambian dinámicamente.Schedulers.single()
: ejecute el trabajo en un solo hilo de manera secuencial y fifo.Schedulers.trampoline()
: Ejecute el trabajo de manera secuencial y fifo en uno de los hilos participantes, generalmente para fines de prueba. Estos están disponibles en todas las plataformas JVM, pero algunas plataformas específicas, como Android, tienen sus propios Scheduler
típicos definidos: AndroidSchedulers.mainThread()
, SwingScheduler.instance()
o JavaFXScheduler.platform()
.
Además, hay una opción para envolver un Executor
existente (y sus subtipos como ExecutorService
) en un Scheduler
a través de Schedulers.from(Executor)
. Esto se puede usar, por ejemplo, para tener un grupo de hilos más grande pero aún fijo (a diferencia computation()
e io()
respectivamente).
El Thread.sleep(2000);
Al final no hay accidente. En RxJava, el Scheduler
predeterminado se ejecuta en los hilos de demonio, lo que significa que una vez que el hilo principal de Java sale, todos se detienen y los cálculos de fondo nunca pueden ocurrir. Dormir durante algún tiempo en este ejemplo de situaciones le permite ver la salida del flujo en la consola con tiempo de sobra.
Los flujos en rxjava son secuenciales de naturaleza divididos en etapas de procesamiento que pueden ejecutarse simultáneamente entre sí:
Flowable . range ( 1 , 10 )
. observeOn ( Schedulers . computation ())
. map ( v -> v * v )
. blockingSubscribe ( System . out :: println );
Este ejemplo de flujo cuadraba los números del 1 al 10 en el Scheduler
de cálculo y consume los resultados en el hilo "principal" (más precisamente, el hilo de llamadas de blockingSubscribe
). Sin embargo, el Lambda v -> v * v
no se ejecuta en paralelo para este flujo; Recibe los valores 1 a 10 en el mismo hilo de cálculo uno tras otro.
Procesar los números 1 a 10 en paralelo es un poco más involucrado:
Flowable . range ( 1 , 10 )
. flatMap ( v ->
Flowable . just ( v )
. subscribeOn ( Schedulers . computation ())
. map ( w -> w * w )
)
. blockingSubscribe ( System . out :: println );
Prácticamente, el paralelismo en Rxjava significa ejecutar flujos independientes y fusionar sus resultados de nuevo en un solo flujo. El Operador flatMap
hace esto mapeando primero cada número de 1 a 10 en su propio Flowable
individual, los ejecuta y fusiona los cuadrados calculados.
Sin embargo, tenga en cuenta que flatMap
no garantiza ningún pedido y que los elementos de los flujos internos puedan terminar entrelazados. Hay operadores alternativos:
concatMap
que mapea y ejecuta un flujo interno a la vez yconcatMapEager
, que ejecuta todos los flujos internos "a la vez", pero el flujo de salida será en el orden se crearon esos flujos internos. Alternativamente, el operador Flowable.parallel()
y el tipo ParallelFlowable
ayudan a lograr el mismo patrón de procesamiento paralelo:
Flowable . range ( 1 , 10 )
. parallel ()
. runOn ( Schedulers . computation ())
. map ( v -> v * v )
. sequential ()
. blockingSubscribe ( System . out :: println );
flatMap
es un operador poderoso y ayuda en muchas situaciones. Por ejemplo, dado un servicio que devuelve un Flowable
, nos gustaría llamar a otro servicio con valores emitidos por el primer servicio:
Flowable < Inventory > inventorySource = warehouse . getInventoryAsync ();
inventorySource
. flatMap ( inventoryItem -> erp . getDemandAsync ( inventoryItem . getId ())
. map ( demand -> "Item " + inventoryItem . getName () + " has demand " + demand ))
. subscribe ( System . out :: println );
A veces, cuando un elemento ha estado disponible, a uno le gustaría realizar algunos cálculos dependientes en él. Esto a veces se llama continuaciones y, dependiendo de lo que suceda y qué tipos estén involucrados, puede involucrar a varios operadores para lograr.
El escenario más típico es dar un valor, invocar otro servicio, esperar y continuar con su resultado:
service . apiCall ()
. flatMap ( value -> service . anotherApiCall ( value ))
. flatMap ( next -> service . finalCall ( next ))
A menudo es el caso también que las secuencias posteriores requerirían valores de mapeos anteriores. Esto se puede lograr moviendo el flatMap
externo a las partes internas de la flatMap
anterior, por ejemplo:
service . apiCall ()
. flatMap ( value ->
service . anotherApiCall ( value )
. flatMap ( next -> service . finalCallBoth ( value , next ))
)
Aquí, el value
original estará disponible dentro del flatMap
interno, cortesía de la captura de variables Lambda.
En otros escenarios, los resultados de la primera fuente/flujo de datos es irrelevante y a uno le gustaría continuar con una fuente cuasi independiente. Aquí, flatMap
también funciona:
Observable continued = sourceObservable . flatMapSingle ( ignored -> someSingleSource )
continued . map ( v -> v . toString ())
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Sin embargo, la continuación en este caso se mantiene Observable
en lugar del Single
probable más apropiado. (Esto es comprensible porque desde la perspectiva de flatMapSingle
, sourceObservable
es una fuente múltiple y, por lo tanto, el mapeo también puede dar como resultado múltiples valores).
A menudo, aunque hay una manera que es algo más expresiva (y también sobre la sobrecarga) al usar el Completable
y su operador y su operador andThen
que reanudar con algo más:
sourceObservable
. ignoreElements () // returns Completable
. andThen ( someSingleSource )
. map ( v -> v . toString ())
La única dependencia entre el sourceObservable
y el someSingleSource
es que el primero debe completarse normalmente para que el segundo se consuma.
A veces, existe una dependencia de datos implícita entre la secuencia anterior y la nueva secuencia que, por alguna razón, no fluía a través de los "canales regulares". Uno se inclinaría a escribir tales continuaciones de la siguiente manera:
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . just ( count . get ()))
. subscribe ( System . out :: println );
Desafortunadamente, esto imprime 0
porque Single.just(count.get())
se evalúa en el momento de ensamblaje cuando el flujo de datos aún no se ha ejecutado. Necesitamos algo que defienda la evaluación de esta fuente Single
hasta el tiempo de ejecución cuando se complete la fuente principal:
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . defer (() -> Single . just ( count . get ())))
. subscribe ( System . out :: println );
o
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . fromCallable (() -> count . get ()))
. subscribe ( System . out :: println );
A veces, una fuente o servicio devuelve un tipo diferente al flujo que se supone que funciona con él. Por ejemplo, en el ejemplo de inventario anterior, getDemandAsync
podría devolver un Single<DemandRecord>
. Si el ejemplo del código se deja sin cambios, esto dará como resultado un error de tiempo de compilación (sin embargo, a menudo con un mensaje de error engañoso sobre la falta de sobrecarga).
En tales situaciones, generalmente hay dos opciones para corregir la transformación: 1) convertir al tipo deseado o 2) Encuentre y use una sobrecarga del operador específico que admite el tipo diferente.
Cada clase de base reactiva presenta operadores que pueden realizar tales conversiones, incluidas las conversiones de protocolo, para que coincidan con otro tipo. La siguiente matriz muestra las opciones de conversión disponibles:
Fluido | Observable | Soltero | Tal vez | Completo | |
---|---|---|---|---|---|
Fluido | 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 | |
Soltero | toFlowable 3 | toObservable | toMaybe | ignoreElement | |
Tal vez | toFlowable 3 | toObservable | toSingle | ignoreElement | |
Completo | toFlowable | toObservable | toSingle | toMaybe |
1 : Al convertir una fuente de valor múltiple en una fuente de valor único, uno debe decidir cuál de los muchos valores de fuente debe considerarse como el resultado.
2 : Convertir un Observable
en Flowable
requiere una decisión adicional: ¿Qué hacer con el flujo potencial sin restricciones de la fuente Observable
? Existen varias estrategias disponibles (como el amortiguador, la caída, el mantenimiento de las últimas) a través del parámetro BackpressureStrategy
o a través de operadores Flowable
estándar como onBackpressureBuffer
, onBackpressureDrop
, onBackpressureLatest
que también permite una mayor personalización del comportamiento de fondo.
3 : Cuando solo hay (como máximo) un elemento fuente, no hay problema con la backpressure, ya que siempre se puede almacenar hasta que la corriente posterior esté lista para consumir.
Muchos operadores de uso frecuente tienen sobrecargas que pueden tratar con los otros tipos. Estos generalmente se nombran con el sufijo del tipo de destino:
Operador | Sobrecarga |
---|---|
flatMap | flatMapSingle , flatMapMaybe , platero, flatMapCompletable , platero, flatMapIterable |
concatMap | concatMapSingle , concatMapMaybe , concatMapCompletable , concatMapIterable |
switchMap | switchMapSingle , switchMapMaybe , switchMapCompletable |
La razón por la que estos operadores tienen un sufijo en lugar de simplemente tener el mismo nombre con una firma diferente es el tipo de borrado. Java no considera firmas como operator(Function<T, Single<R>>)
y operator(Function<T, Maybe<R>>)
diferente (a diferencia de C#) y debido a la borrado, los dos operator
terminarían como métodos duplicados con la misma firma.
Nombrar en la programación es una de las cosas más difíciles, ya que se espera que los nombres no sean largos, expresivos, capturados y fácilmente memorables. Desafortunadamente, el lenguaje de destino (y las convenciones preexistentes) pueden no dar demasiada ayuda a este respecto (palabras clave inutilizables, borrado de tipo, ambigüedades de tipo, etc.).
En el RX.NET original, el operador que emite un solo elemento y luego se completa se llama Return(T)
. Dado que la convención de Java es tener una letra en minúscula que inicie un nombre de método, esto habría sido return(T)
que es una palabra clave en Java y, por lo tanto, no está disponible. Por lo tanto, Rxjava eligió nombrar a este operador just(T)
. Existe la misma limitación para el Switch
del operador, que tuvo que llamarse switchOnNext
. Otro ejemplo es Catch
que se llamó onErrorResumeNext
.
Muchos operadores que esperan que el usuario proporcione alguna función que devuelva un tipo reactivo no se puede sobrecargar porque el tipo de borrado alrededor de una Function<T, X>
convierte tales firmas de método en duplicados. Rxjava eligió nombrar a dichos operadores al agregar el tipo como sufijo también:
Flowable < R > flatMap ( Function <? super T , ? extends Publisher <? extends R >> mapper )
Flowable < R > flatMapMaybe ( Function <? super T , ? extends MaybeSource <? extends R >> mapper )
A pesar de que ciertos operadores no tienen problemas con el borrado de tipo, su firma puede ser ambigua, especialmente si uno usa Java 8 y Lambdas. Por ejemplo, hay varias sobrecargas de concatWith
que toman los otros tipos de base reactivos como argumentos (para proporcionar conveniencia y beneficios de rendimiento en la implementación subyacente):
Flowable < T > concatWith ( Publisher <? extends T > other );
Flowable < T > concatWith ( SingleSource <? extends T > other );
Tanto Publisher
como SingleSource
aparecen como interfaces funcionales (tipos con un método abstracto) y pueden alentar a los usuarios a tratar de proporcionar una expresión de Lambda:
someSource . concatWith ( s -> Single . just ( 2 ))
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Desafortunadamente, este enfoque no funciona y el ejemplo no imprime 2
en absoluto. De hecho, desde la versión 2.1.10, ni siquiera se compila porque existen al menos 4 concatWith
las sobrecargas y el compilador encuentra el código anterior ambiguo.
El usuario en tales situaciones probablemente quería diferir algún cálculo hasta que el someSource
se haya completado, por lo que el operador inequívoco correcto debería haber sido defer
:
someSource . concatWith ( Single . defer (() -> Single . just ( 2 )))
. subscribe ( System . out :: println , Throwable :: printStackTrace );
A veces, se agrega un sufijo para evitar ambigüedades lógicas que pueden compilar pero producir el tipo incorrecto en un flujo:
Flowable < T > merge ( Publisher <? extends Publisher <? extends T >> sources );
Flowable < T > mergeArray ( Publisher <? extends T >... sources );
Esto también puede ser ambiguo cuando los tipos de interfaz funcional se involucran como el argumento de tipo T
.
Los flujos de datos pueden fallar, momento en el que se emite el error al consumidor. Sin embargo, a veces, múltiples fuentes pueden fallar, momento en el que hay una opción, ya sea que espere o no a que todos se completen o falle. Para indicar esta oportunidad, muchos nombres de operadores se sufre con las palabras DelayError
(mientras que otros cuentan con una bandera booleana de delayError
o delayErrors
en una de sus sobrecargas):
Flowable < T > concat ( Publisher <? extends Publisher <? extends T >> sources );
Flowable < T > concatDelayError ( Publisher <? extends Publisher <? extends T >> sources );
Por supuesto, pueden aparecer sufijos de varios tipos:
Flowable < T > concatArrayEagerDelayError ( Publisher <? extends T >... sources );
Las clases base pueden considerarse pesadas debido a la gran cantidad de métodos estáticos e de instancia en ellas. El diseño de Rxjava 3 fue fuertemente influenciado por la especificación de las transmisiones reactivas, por lo tanto, la biblioteca presenta una clase y una interfaz por cada tipo reactivo:
Tipo | Clase | Interfaz | Consumidor |
---|---|---|---|
0..n backpresado | Flowable | Publisher 1 | Subscriber |
0..n sin dejar de lado | Observable | ObservableSource 2 | Observer |
1 elemento o error | Single | SingleSource | SingleObserver |
0..1 elemento o error | Maybe | MaybeSource | MaybeObserver |
0 elemento o error | Completable | CompletableSource | CompletableObserver |
1 El org.reactivestreams.Publisher
es parte de la biblioteca de transmisiones reactivas externas. Es el tipo principal que interactúa con otras bibliotecas reactivas a través de un mecanismo estandarizado regido por la especificación de corrientes reactivas.
2 La convención de nombres de la interfaz fue agregar Source
al nombre de clase semi-tradicional. No hay FlowableSource
ya que Publisher
es proporcionado por la Biblioteca Reactive Streams (y la subtipación tampoco habría ayudado con la interoperación). Sin embargo, estas interfaces no son estándar en el sentido de la especificación de las transmisiones reactivas y actualmente son específicas de RXJAVA solamente.
Por defecto, RxJava en sí no requiere ninguna configuración de proaguard/R8 y debe funcionar sin problemas. Desafortunadamente, la dependencia de las transmisiones reactivas desde la versión 1.0.3 ha incrustado archivos de clase Java 9 en su jar que pueden causar advertencias con el proguard 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
Se recomienda que uno establezca la siguiente entrada -dontwarn
en el archivo de proguard-ruleset
de la aplicación:
-dontwarn java.util.concurrent.Flow*
Para R8, el jar RxJava incluye el META-INF/proguard/rxjava3.pro
con la misma cláusula de no advertencia y debe aplicarse automáticamente.
Para más detalles, consulte el wiki.
La versión 3.x está en desarrollo. Las correcciones de errores se aplicarán a las ramas 2.x y 3.x, pero solo se agregarán nuevas características a 3.x.
Se producirán incrementos menores 3.x (como 3.1, 3.2, etc.) cuando se agregue una nueva funcionalidad no trivial o se producen mejoras significativas o correcciones de errores que pueden tener cambios de comportamiento que pueden afectar algunos casos de borde (como la dependencia del comportamiento resultante de un error). Un ejemplo de una mejora que se clasificaría, ya que esto es agregar soporte de retroceso reactivo a un operador que anteriormente no lo admitía. Esto debería ser compatible con retroceso, pero se comporta de manera diferente.
Los incrementos del parche 3.xy (como 3.0.0 -> 3.0.1, 3.3.1 -> 3.3.2, etc.) se producirán para las correcciones de errores y la funcionalidad trivial (como agregar una sobrecarga de métodos). También se puede agregar una nueva funcionalidad marcada con una anotación @Beta
o @Experimental
en las versiones de parche para permitir una exploración rápida e iteración de una nueva funcionalidad inestable.
Las API marcadas con la anotación @Beta
a nivel de clase o método están sujetas a cambios. Se pueden modificar de cualquier manera, o incluso eliminar, en cualquier momento. Si su código es una biblioteca en sí (es decir, se usa en la clase de usuarios fuera de su control), no debe usar API beta, a menos que las vuelva a empaquetar (por ejemplo, usando Proguard, sombreado, etc.).
Las API marcadas con la anotación @Experimental
a nivel de clase o método casi seguramente cambiarán. Se pueden modificar de cualquier manera, o incluso eliminar, en cualquier momento. No debe usarlos ni confiar en ellos en ningún código de producción. Son puramente para permitir pruebas y comentarios amplios.
Las API marcadas con la anotación @Deprecated
a nivel de clase o método permanecerán compatibles hasta la próxima versión principal, pero se recomienda dejar de usarlos.
Todo el código dentro del io.reactivex.rxjava3.internal.*
Los paquetes se consideran API privado y no se deben confiar en absoluto. Puede cambiar en cualquier momento.
http://reactivex.io/RxJava/3.x/javadoc/3.xy/
Los binarios y la información de dependencia para Maven, Ivy, Gradle y otros se pueden encontrar en http://search.maven.org.
Ejemplo para Gradle:
implementation ' io.reactivex.rxjava3:rxjava:x.y.z '
Y para Maven:
< dependency >
< groupId >io.reactivex.rxjava3</ groupId >
< artifactId >rxjava</ artifactId >
< version >x.y.z</ version >
</ dependency >
Y para la hiedra:
< dependency org = " io.reactivex.rxjava3 " name = " rxjava " rev = " x.y.z " />
Las instantáneas después del 1 de mayo, 2021 están disponibles a través de 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 '
}
Las instantáneas de Javadoc están disponibles en http://reactivex.io/rxjava/3.x/javadoc/snapshot
Para construir:
$ git clone [email protected]:ReactiveX/RxJava.git
$ cd RxJava/
$ ./gradlew build
Se pueden encontrar más detalles sobre la construcción en la página de inicio del wiki.
Para errores, preguntas y discusiones, utilice los problemas 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.