La programación reactiva es un concepto que se ha popularizado en los últimos años, especialmente en Android, gracias a la aparición de Frameworks como RxJava.
La realidad es que esta idea ya lleva mucho tiempo dando vueltas, y es mucho más sencilla de lo que parece.
Hoy te quiero desmitificar esta idea, que comprendas qué es exactamente la programación reactiva, y qué problemas te suele solucionar en el día a día.
Este artículo forma parte de una serie en la que te voy a contar cómo puedes iniciarte con Flow, la apuesta de Kotlin por la programación reactiva, que además se integra con las corrutinas.
Si no quieres perderte nada, te animo a que te suscribas a mi canal de YouTube, donde irás estando al día de los vídeos publicados.
Qué es la programación reactiva
En la programación clásica, todo se basa en acciones que nosotros realizamos activamente:
- Si queremos algo de la base de datos
- Si necesitamos algo de un servidor
- Si queremos recoger información de un sensor del dispositivo
- Si estamos usando la localización del usuario
Lo que hacemos en cada caso es ir y preguntarle “oye, ¿qué datos tienes para mí ahora mismo?
En la programación reactiva, le damos la vuelta a la idea. La forma de trabajar sería “estoy interesado en tus datos, cada vez que haya un cambio infórmame”.
Nos encontramos entonces con un software que se actualiza solo cuando las fuentes de datos de las que dependen se modifican.
Esto es especialmente interesante en interfaces de usuario, ya que muchas veces necesitamos actualizaciones en tiempo real de la información que estamos viendo, y muchas veces va a ser difícil descubrir cuándo algo se ha modificado.
Tradicionalmente se han hecho muchas “chapuzas” para solucionar estas situaciones, como hacer peticiones cada x tiempo para comprobar si ha habido cambios, pero la programación reactiva permite hacer esto de forma mucho más sencilla.
Patrón Observer
¿Qué tal si en vez de pedir los datos, se nos informara cada vez que han cambiado? La programación reactiva, simplificando mucho, no es más que la implementación del patrón Observer.
En este patrón, tenemos un objeto Observable
al que podemos suscribirnos, y cada vez que haya un cambio en su valor seremos informados.

Actores en la programación reactiva
Por tanto, podríamos decir que tenemos los siguientes actores en la programación reactiva:
Flujos de datos
Son datos que se van modificando cada cierto tiempo, y que puede tener interés observar en tiempo real.
- En una base de datos o un servidor, cada vez que se modifica cierto valor
- En un sensor, cada vez que el valor del sensor cambia
- En la localización, cada vez que el usuario se mueve y el punto de localización cambia
Observable
Un componente que puede ser observado, y que se encargará de informar cuando ese flujo de datos se modifique.
Normalmente este y el anterior están unidos, pero quiero dejar estos conceptos separados de momento.
Observer (u observador)
Es el elemento que observa esas modificaciones. Cuando el dato se modifica, se notifica al componente que lo está utilizando.
Normalmente este observer necesita suscribirse cuando quiere empezar a recibir datos, y desuscribirse cuando ya no le interesan más esos datos.
¿Y ya está?
Bueno, a grandes rasgos sí, pero la realidad es un poco más compleja.
La cosa se complica cuando tenemos distintos flujos de datos, queremos combinarlos mediante distintas operaciones, y hacer que ciertas cosas se ejecuten en unos hilos y otras en otros.
A veces la generación de eso datos requiere de operaciones complejas, o que van a bloquear mucho tiempo el hilo principal, y es importante tener una forma sencilla de no liarla en este aspecto.
Así que podría decirse que podemos tener un par de elementos más, que no son indispensables pero que son muy útiles
Dispatchers o Schedulers
En cada framework de programación reactiva se llaman de una forma distinta, pero básicamente son un conjunto de hilos donde se van a ejecutar las operaciones, y unas reglas que optimizan su uso para ser lo más eficientes posibles.
Cada operación se ejecutará en el que le digamos, para de esa forma liberar el hilo principal y optimizar recursos. Suele haber 3 tipos:
- UI: Es el hilo donde se pinta la interfaz de usuario
- I/O: para operaciones de entrada/salida que no requieren de trabajo del procesador: esperar que responda una base de datos, un servidor, un sensor, el sistema de archivos…
- Computación: para tareas que requieren del uso intensivo de la CPU. Es decir, algoritmos propios del programa.
Si has usado corrutinas, seguramente todo esto te suena ya. Por orden serían Dispatchers.Main
, Dispatchers.IO
y Dispatchers.Default
.
Había personas que solo por esta funcionalidad ya usaban RxJava, pero era un poco como matar moscas a cañonazos, porque como ves no es la parte importante de la programación reactiva, es solo un añadido para simplificar las cosas.
Operadores sobre flujos de datos
Aquí es donde la cosa se suele complicar. Existen montones de operadores que nos permiten modificar y combinar flujos de datos, y conocerlos todos es muy complicado.
En RxJava, esto suele ser lo que mayor curva de aprendizaje conlleva.
Por suerte, con Flow los operadores son los mismos que los que usamos en las colecciones de Kotlin, por lo que es bastante más sencillo de aprender. Aquí de momento no vamos a entrar mucho.
Vamos a crear nuestro propio sistema de programación reactiva
Sí, como lo oyes. En este primer artículo no vamos a usar ningún framework, sino que lo vamos a crear nosotros mismos. Realmente te hablaré de uno que igual no te esperas al final, pero no nos adelantemos.
Imaginemos que tenemos una serie de datos que se van generando de forma automática, y que tenemos que actualizar un RecyclerView cada vez que ese dato cambia.
Lo primero que necesitaremos es crearnos una estructura de datos que nos permita observar un dato y cuándo se modifica:
class Observable<T>(var value: T) { private var observers: MutableList<(T) -> Unit> = mutableListOf() fun subscribe(observer: (T) -> Unit) { observers.add(observer) observer(value) } fun unsubscribe(observer: (T) -> Unit) { observers.remove(observer) } fun updateValue(newValue: T) { value = newValue notifyObservers() } private fun notifyObservers() { observers.forEach { it(value) } } }
Las partes importantes son que hay un dato, un listado de observers, y unas funciones para suscribirse, desuscribirse, y actualizar el valor.
Si te pierdes un poco con el código Kotlin que hay aquí, te animo a que te apuntes a mi training gratuito para que descubras cómo empezar, cómo sacarle el máximo partido al lenguaje, y por qué necesitas aprenderlo si eres desarrollador/a Android.
Haz click aquí para unirte ahora.
Luego creamos un objeto que contenga el observable y que permita empezar a emitir valores. Esto se lanzará en el Application a modo de ejemplo:
object ItemsProvider { val observable = Observable<List<String>>(emptyList()) private var values = emptyList<String>() private val random = Random(System.currentTimeMillis()) fun startEmitting() { GlobalScope.launch(Dispatchers.Main) { while (true) { delay(1000) values = values + random.nextInt().toString() observable.updateValue(values) } } } }
Y finalmente, lo único que habría que hacer desde la Activity es suscribirse en el onCreate()
y desuscribirse en el onDestroy()
, y crear el observer para escuchar los cambios:
private val observer = { items: List<String> -> adapter.items = items } override fun onCreate(savedInstanceState: Bundle?) { ... ItemsProvider.observable.subscribe(observer) } override fun onDestroy() { ItemsProvider.observable.unsubscribe(observer) super.onDestroy() }
LiveData y la Programación Reactiva
Si te fijas, si ya usabas LiveData
en tus proyectos, todo esto te sonará mucho. Este componente de la librería de Lifecycle
de Android hace prácticamente lo mismo, y además es capaz de observar el ciclo de vida de la Activity
, así que ni siquiera necesitamos desuscribirnos:
object ItemsProvider { private val _observable = MutableLiveData<List<String>>() val observable: LiveData<List<String>> get() = _observable ... }
Y en la Activity
:
ItemsProvider.observable.observe(this, Observer { adapter.items = it })
Si quieres aprender más sobre LiveData, ya hablé sobre ellos en mi artículo sobre MVVM.
Conclusión
Como ves, los conceptos realmente son muy sencillos.
En Programación Reactiva, en lugar de ir nosotros activamente a buscar los datos, existen unos flujos de datos a los que nosotros reaccionamos cuando recibimos nueva información.
Aquí me he permitido algunas licencias con el objetivo de entender bien la bases, pero en los siguientes artículos nos iremos adentrando más a fondo en los conceptos.
Y sobre todo en cómo usar Flow: la librería basada en corrutinas que nos permite implementar la programación Reactiva en Kotlin y en Android.
Tienes el código subido en este repositorio de GitHub.
Y de nuevo, si no quieres perderte nada, y prefieres ver este contenido en vídeo, únete a mi canal de YouTube. ¡Nos vemos por allí!
Corrutinas en Kotlin 1.3: funciones de suspensión, contexts, builders y scopes
Las corrutinas son una de las características más interesantes de Kotlin. Con ellas, se puede simplificar el trabajo de las tareas asíncronas de una manera impresionante y hacer que el código sea...
Secuencias de Kotlin (Sequences): Qué son y cómo usarlas
Entre las colecciones de Kotlin existen unas muy peculiares: las secuencias. Las secuencias se diferencian del resto de colecciones en que, en vez de contener una serie de objetos ya disponibles...
Flows en Kotlin: Todo lo que necesitas saber
Flow es un componente de la librería de corrutinas que nos permite implementar la programación reactiva. Es el sustituto natural de RxJava, ya que la gran mayoría de las cosas que se pueden hacer...
Usando Flow en un proyecto Android
En el artículo anterior veíamos un ejemplo sobre Flow, pero eran los típicos ejemplos que en el día a día no nos llevan a ninguna parte. ¿Cómo encaja todo esto dentro de una aplicación Android?...
Room con Flow, y un ejemplo de paginación
Esto avanza, y si en el artículo anterior veíamos cómo usar Flow en un proyecto Android, aquí vamos a ir más allá e integrarlo con Flow. En realidad la integración es extremadamente sencilla,...
StateFlow, el sustituto natural de LiveData
Llevamos una serie de capítulos dedicados a Flow, donde hemos visto desde los conceptos básicos de Flow hasta cómo usar Flow en un ejemplo real. Incluso hemos visto cómo Flow se integra con Room....
Convertir cualquier callback en un Flow con CallbackFlow
Existen varios tipos de Flows muy particulares que nos van a solucionar la vida cuando tengamos que hacer cosas muy concretas. Ya vimos StateFlow en un artículo anterior, y en esta ocasión...
Cómo hacer tests de Corrutinas y Flows – Paso a Paso
¡Vaya viaje por el que hemos pasado en estos artículos! Hace ya varios de ellos empezamos hablando sobre la programación reactiva con Flow, y hemos aprendido un montón de conceptos e ideas sobre...
2 formas de recolectar Flows en la UI que SÍ funcionan
En la serie de artículos sobre Programación Reactiva con Flow hemos visto muchos conceptos, y hemos aprendido cómo aplicarlos al desarrollo Android. Pero hay algo que no hemos hecho del todo...
0 comentarios