RxJava es una biblioteca de programación reactiva para la JVM que implementa flujos de datos asíncronos mediante el patrón Observable con operadores funcionales de transformación. Porta los conceptos de ReactiveX a Java y Kotlin, proporcionando una API unificada para trabajar con peticiones de red, bases de datos, eventos de UI y tareas en segundo plano. Según ReactiveX, 2025, la biblioteca se utiliza en más de 120 000 proyectos en GitHub y es el estándar de programación reactiva para Android hasta la llegada de Kotlin Flow. RxJava reemplaza AsyncTask, Loader y callbacks con una única cadena de procesamiento de datos.
Puntos clave
RxJava es una implementación de la biblioteca ReactiveX (Reactive Extensions) para la Máquina Virtual de Java. La primera versión de RxJava fue lanzada por Netflix en 2013 para gestionar llamadas asíncronas en aplicaciones del lado del servidor. En el momento de su creación, las principales alternativas en Java eran Future y Callback — ambos enfoques conducían a callback-hell y una gestión compleja de hilos. RxJava introdujo la composición de operaciones asíncronas mediante Observable con cadenas de operadores funcionales.
La arquitectura de RxJava se basa en la especificación Reactive Streams — un estándar para el procesamiento asíncrono de flujos con contrapresión no bloqueante. La especificación define cuatro interfaces: Publisher, Subscriber, Subscription y Processor. RxJava 2+ implementa completamente Reactive Streams mediante el tipo Flowable, cumpliendo con los contratos de contrapresión a diferencia de RxJava 1. Observable en RxJava 2 no soporta contrapresión — está diseñado para flujos con un número pequeño de eventos o eventos de UI.
Según la encuesta de JetBrains, 2025, RxJava se encuentra entre las 3 bibliotecas principales para el desarrollo de Android. Los casos de uso principales incluyen: manejo de peticiones de red mediante Retrofit (integrado con RxJava a través de CallAdapter), trabajo con Room (las consultas reactivas devuelven Flowable o Maybe), animaciones y eventos de UI mediante RxBinding, y búsqueda con debounce en la entrada de texto. Todos estos escenarios comparten un patrón de cadena común: fuente (Observable) → transformación (operadores) → suscripción (subscribe).
RxJava 1 (2013) sentó las bases con Observable y operadores, pero sufría problemas de contrapresión — en flujos rápidos, los datos se acumulaban en memoria, causando OutOfMemoryError. RxJava 2 (2016) corrigió la arquitectura separando Observable (sin contrapresión) y Flowable (con contrapresión). RxJava 3 (2020) añadió soporte para Java 8 Stream API, operadores adicionales y un mejor rendimiento de suscripción. Actualmente, RxJava 3 es la versión recomendada para nuevos proyectos.
RxJava proporciona cinco tipos principales de fuentes reactivas, cada una diseñada para un escenario específico. Observable y Flowable emiten múltiples valores, Single emite un valor o un error, Completable emite solo la finalización sin datos, y Maybe emite un valor, cero o un error. Elegir el tipo correcto reduce el volumen de código y hace que la cadena sea autodocumentada.
| Tipo | Número de eventos | Contrapresión | Escenario |
|---|---|---|---|
| Observable | 0..N, luego finaliza | No | Eventos de UI, flujos cortos |
| Flowable | 0..N, luego finaliza | Sí | Respuestas de red, flujos de BD |
| Single | Exactamente 1 o error | No | Petición HTTP, lectura de un registro |
| Completable | 0 (solo finalización) | No | Escritura en BD, envío de evento |
| Maybe | 0, 1 o error | No | Caché: valor existe o no |
Flowable es el tipo más flexible para trabajar con grandes flujos de datos. Implementa el Publisher de Reactive Streams con soporte de contrapresión: el consumidor puede solicitar un número específico de elementos mediante Subscription.request(n). Esto evita el desbordamiento del búfer cuando las velocidades del productor y consumidor no coinciden. Si la contrapresión no es crítica, use Observable — tiene menos sobrecarga debido a la ausencia del mecanismo request.
Single es la elección óptima para peticiones HTTP. Retrofit 2 con RxJava CallAdapter devuelve Single<ResponseBody> para cada petición. Single garantiza exactamente una llamada a onSuccess u onError, lo que coincide con la semántica de una petición HTTP — una respuesta o un error. Completable se usa para operaciones de escritura que no devuelven datos: insert, update, delete. Maybe es conveniente para verificar la caché — puede devolver un valor o no.
// Ejemplo de uso de Single para una petición HTTP
interface ApiService {
@GET("users/{id}")
fun getUser(@Path("id") userId: Int): Single<User>
}
// Suscripción con procesamiento en el hilo principal
apiService.getUser(42)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ user ->
textView.text = user.name
}, { error ->
Log.e("API", "Error: ${error.message}")
})
.addTo(compositeDisposable)
Los operadores de RxJava son funciones de orden superior que toman una fuente reactiva y devuelven otra, transformando el flujo de datos. RxJava 3 contiene más de 400 operadores, divididos en categorías: transformación, filtrado, combinación, manejo de errores y gestión del tiempo. Cada operador es perezoso — la cadena se construye en la declaración y se ejecuta al suscribirse.
map es el operador básico que transforma cada valor mediante una función. flatMap toma una función que devuelve un Observable para cada elemento y aplana el resultado en un único flujo. switchMap es similar a flatMap, pero cuando llega un nuevo elemento, se desuscribe del Observable anterior. concatMap preserva el orden de los elementos — a diferencia de flatMap, se suscribe secuencialmente a cada Observable anidado.
// Análisis JSON con transformación y filtrado
apiService.getUsers()
.flatMap { users ->
Observable.fromIterable(users)
}
.filter { user ->
user.age >= 18
}
.map { user ->
UserDto(user.name, user.age)
}
.toList()
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ adapter.submitList(it) },
{ Log.e("Error", it.message) })
Combinación de flujos es un área donde RxJava destaca especialmente. zip combina elementos de múltiples Observables por pares según el índice: primero con primero, segundo con segundo. combineLatest emite un nuevo valor cuando cualquier flujo cambia, combinando los valores más recientes de todos los flujos. merge combina múltiples Observables en uno, preservando el orden de llegada de los eventos. concat se suscribe secuencialmente a cada Observable y pasa todos sus eventos antes de pasar al siguiente.
Gestión del tiempo incluye debounce (esperar una pausa en el flujo antes de emitir), throttleFirst (emitir el primer evento, ignorar el resto dentro de una ventana), timeout (error si no llega un evento en el intervalo). La búsqueda con debounce en la entrada de texto es el escenario más común: searchObservable.debounce(300, MILLISECONDS).distinctUntilChanged() evita peticiones innecesarias durante la escritura rápida.
| Categoría | Operador | Comportamiento |
|---|---|---|
| Transformación | map / flatMap / switchMap | Transformar un valor o flujo |
| Filtrado | filter / distinct / take | Seleccionar valores por condición |
| Combinación | zip / combineLatest / merge | Combinar 2+ flujos |
| Errores | onErrorResumeNext / retry | Recuperarse de fallos |
| Utilidades | delay / timeout / debounce | Gestión del tiempo en flujos |
Scheduler en RxJava es una abstracción sobre un grupo de hilos. La biblioteca proporciona cinco Schedulers incorporados: Schedulers.io() para operaciones de E/S (red, archivos), Schedulers.computation() para tareas intensivas de CPU, Schedulers.newThread() para un nuevo hilo cada vez, Schedulers.single() para ejecución en un solo hilo y Schedulers.trampoline() para ejecución inmediata en el hilo actual.
subscribeOn determina en qué Scheduler se ejecuta el Observable fuente. Si hay varios subscribeOn en la cadena, tiene prioridad el más cercano a la fuente. observeOn cambia el downstream al Scheduler especificado — cada uso de observeOn cambia el hilo para los operadores siguientes. Un patrón típico de Android: subscribeOn(Schedulers.io()) para operaciones de red, observeOn(AndroidSchedulers.mainThread()) para actualizaciones de UI.
// Procesamiento multihilo con cambio de contexto
Observable.fromCallable(() -> database.getItems())
.subscribeOn(Schedulers.io()) // BD en io
.map(items -> processItems(items)) // transformación en io
.observeOn(Schedulers.computation()) // cambiar a computation
.map(processed -> compressImages(processed))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> ui.showResult(result))
AndroidSchedulers.mainThread() es un Scheduler de la biblioteca RxAndroid que ejecuta código en el hilo principal de Android. Es obligatorio para cualquier actualización de UI en una cadena reactiva. La biblioteca usa Handler internamente y garantiza la ejecución en el hilo de UI incluso bajo alta carga. Para operaciones en segundo plano, Schedulers.io() admite un grupo de hilos ilimitado y es adecuado para cualquier operación bloqueante. Schedulers.computation() usa un grupo fijo igual al número de núcleos de CPU.
RxJava en Android se usa para tres escenarios principales: consultas reactivas a Room, integración con Retrofit y vinculación reactiva de UI mediante RxBinding. Cada escenario tiene su propio conjunto de tipos: Room devuelve Flowable para consultas observables, Retrofit devuelve Single para peticiones HTTP, RxBinding devuelve Observable para eventos de UI.
Room es una biblioteca de persistencia de Google. A partir de Room 2.1, la base de datos admite tipos de retorno reactivos: Flowable y Observable. Cuando cualquier registro en la tabla cambia, Room envía automáticamente un nuevo valor al flujo. El desarrollador se suscribe a Flowable en el ViewModel y recibe datos actualizados sin consultas manuales en cada cambio.
// Room DAO con consulta reactiva
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :id")
fun getUserById(@Param("id") userId: Int): Flowable<User>
@Insert
fun insertUser(user: User): Completable
}
// ViewModel — composición Room + Network
class UserViewModel(private val dao: UserDao) : ViewModel() {
val users: Flowable<List<User>> = dao.getAllUsers()
.subscribeOn(Schedulers.io())
}
El patrón MVVM + RxJava se basa en que el ViewModel no tiene referencias a la Vista. El ViewModel publica fuentes reactivas (Flowable, LiveData mediante Transformations), y la Activity o Fragment se suscriben a ellas. Esto proporciona testabilidad: el ViewModel se prueba sin la UI, sustituyendo los Schedulers mediante RxJavaPlugins.setComputationScheduler. CompositeDisposable en el ViewModel gestiona el ciclo de vida de las suscripciones — al llamar a onCleared(), todas las suscripciones se cancelan.
Kotlin Flow es una implementación nativa de flujos fríos en Kotlin, integrada en corrutinas y presentada en Kotlin 1.3. Flow resuelve los mismos problemas que RxJava pero con diferencias fundamentales: soporte integrado de corrutinas (funciones suspend), cancelación mediante coroutine cancellation y ausencia de problemas de contrapresión — Flow usa suspend en lugar de almacenamiento en búfer. Flow es parte de la biblioteca estándar de Kotlin, sin requerir dependencias adicionales.
RxJava sigue siendo la opción preferida para proyectos en Java, proyectos que soportan Java 7-8 y bases de código existentes en RxJava. El ecosistema de RxJava es significativamente más rico: más de 400 operadores frente a unos 50 en Flow, integración con Retrofit mediante un CallAdapter incorporado, soporte de contrapresión mediante Flowable, y RxBinding, RxPermissions, RxLocation para Android. Kotlin Flow está alcanzando rápidamente, pero la flexibilidad de RxJava en escenarios complejos de combinación de flujos sigue siendo superior.
| Característica | RxJava | Kotlin Flow |
|---|---|---|
| Idioma | Java / Kotlin | Solo Kotlin |
| Cancelación | Disposable / CompositeDisposable | Coroutine cancellation |
| Contrapresión | Flowable (estrategias BUFFER, DROP, LATEST) | Mediante conflate / buffer |
| Operadores | 400+ | ~50 (extensible) |
| Integración con Room | Flowable, Observable | Flow, StateFlow |
| ViewModel | CompositeDisposable | viewModelScope + Flow |
Preguntas frecuentes
Observable no soporta contrapresión — si el productor es más rápido que el consumidor, los eventos se acumulan en memoria. Flowable implementa Reactive Streams con contrapresión mediante Subscription.request(), evitando el desbordamiento del búfer cuando las velocidades no coinciden.
Single se usa para operaciones que devuelven exactamente un valor o un error: peticiones HTTP, lectura de un único registro de BD, cálculo de un resultado. Single corresponde semánticamente a Future y reduce el código eliminando onComplete no utilizado.
El método dispose() en Disposable cancela una suscripción. Para la gestión grupal se usa CompositeDisposable — recolecta todos los Disposables y los elimina simultáneamente al llamar a clear(). El lugar típico es onCleared() en ViewModel o onPause() en Activity.
flatMap se suscribe a todos los Observables anidados y combina sus eventos en orden arbitrario. switchMap se desuscribe del Observable anterior cuando llega un nuevo elemento y se suscribe al nuevo. switchMap se usa en búsquedas — cada nueva petición cancela la anterior.
Para nuevos proyectos en Kotlin, Flow es preferible debido a la integración con corrutinas y su menor tamaño. Para proyectos existentes en RxJava, la migración se justifica solo si toda la base de código se está moviendo a corrutinas — el uso intermedio de ambas bibliotecas complica la arquitectura.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también