Programación reactiva de Kotlin con RxJava y RxKotlin

Desde que se convirtió en un lenguaje oficialmente compatible para el desarrollo de Android, Kotlin ha crecido rápidamente en popularidad entre los desarrolladores de Android, con Google reportando un aumento 6x en las aplicaciones que se crean usando Kotlin.

Si ya ha utilizado RxJava o RxAndroid y desea cambiar a Kotlin, o desea iniciar la programación reactiva con Kotlin, este tutorial es para usted. Cubriremos lo esencial para crear RxJava 2.0. Observadores, Observables y flujos de datos en Kotlin, antes de ver cómo puede recortar una tonelada de código repetitivo de sus proyectos, combinando RxJava con las funciones de extensión de Kotlin.

Usar RxJava con Kotlin puede ayudarlo a crear aplicaciones altamente reactivas en menos código, pero ningún lenguaje de programación es perfecto, por lo que también compartiré una solución para el problema de conversión de SAM que muchos desarrolladores encuentran cuando comienzan a usar RxJava 2.0 con Kotlin..

Para resumir, crearemos una aplicación que demuestre cómo podría usar RxJava para resolver algunos de los problemas que se presentan en proyectos de Android de la vida real..

Si esta es la primera vez que prueba RxJava, a lo largo del camino también le proporcionaré toda la información de fondo que necesita para comprender los conceptos básicos de RxJava. Incluso si nunca antes has experimentado con RxJava, al final de este artículo tendrás una comprensión sólida de cómo usar esta biblioteca en tus proyectos., y habrás creado varias aplicaciones de trabajo, usando RxJava, RxKotlin, RxAndroid y RxBinding.

Qué es RxJava, de todos modos?

RxJava es una implementación de código abierto de la biblioteca ReactiveX que le ayuda a crear aplicaciones en el estilo de programación reactiva. Aunque RxJava está diseñado para procesar flujos de datos síncronos y asíncronos, no está restringido a los tipos de datos "tradicionales". La definición de "datos" de RxJava es bastante amplia e incluye cosas como cachés, variables, propiedades e incluso eventos de entrada de usuarios como clics y swipes. Solo porque su aplicación no se ocupa de grandes números ni realiza transformaciones de datos complejas, no significa que no pueda beneficiarse de RxJava!

Para obtener información sobre el uso de RxJava para aplicaciones de Android, puede consultar algunas de mis otras publicaciones aquí en Envato Tuts+.

Entonces, ¿cómo funciona RxJava?

RxJava extiende el patrón de diseño del software Observer, que se basa en el concepto de observadores y observables. Para crear un flujo de datos básico de RxJava, necesita:

  • Crear un observable.
  • Dale al Observable algunos datos para emitir..  
  • Crear un observador.
  • Suscriba al observador a lo observable.

Tan pronto como el Observable tenga al menos un Observador, comenzará a emitir datos. Cada vez que el observable emite un dato, notificará al observador asignado llamando al En el siguiente() método, y el observador normalmente realizará alguna acción en respuesta a esta emisión de datos. Una vez que el Observable haya terminado de emitir datos, notificará al Observador llamando al onComplete (). El Observable terminará y la secuencia de datos finalizará..

Si ocurre una excepción, entonces onError () se llamará, y el Observable terminará inmediatamente sin emitir más datos ni llamadas onComplete ().

Pero RxJava no es sólo acerca de pasar datos de un observable a un observador! RxJava tiene una gran colección de operadores que puede utilizar para filtrar, combinar y transformar estos datos. Por ejemplo, imagina que tu aplicación tiene un Pague ahora botón que detecta al hacer clic eventos, y le preocupa que un usuario impaciente pueda presionar el botón varias veces, lo que hace que su aplicación procese varios pagos.  

RxJava te permite transformar estos al hacer clic eventos en un flujo de datos, que luego puede manipular usando los diversos operadores de RxJava. En este ejemplo en particular, podría usar el rebotar () operador para filtrar las emisiones de datos que suceden en una sucesión rápida, por lo que incluso si el usuario rechaza Pague ahora botón, su aplicación solo registrará un solo pago.

¿Cuáles son los beneficios de usar RxJava??

Hemos visto cómo RxJava puede ayudarlo a resolver un problema específico, en una aplicación específica, pero ¿qué tiene para ofrecer proyectos de Android, en general??

RxJava puede ayudar a simplificar su código al brindarle una manera de escribir lo que desea lograr, en lugar de escribir una lista de instrucciones con las que debe trabajar su aplicación. Por ejemplo, si quisiera ignorar todas las emisiones de datos que ocurren dentro del mismo período de 500 milisegundos, entonces escribiría:

.debounce (500, TimeUnit.MILLISECONDS)

Además, desde RxJava se trata. casi todo como datos, proporciona una plantilla que puede aplicar a una amplia gama de eventos: crear un observable, crear un observador, suscribir el observador al observable, enjuagar y repetir. Este enfoque de fórmula da como resultado un código mucho más directo y legible para el ser humano.

El otro beneficio importante para los desarrolladores de Android es que RxJava puede eliminar gran parte del dolor de los subprocesos múltiples en Android. Los usuarios móviles de hoy esperan que sus aplicaciones puedan realizar múltiples tareas, incluso si es algo tan simple como descargar datos en segundo plano sin dejar de responder a las aportaciones de los usuarios.

Android tiene varias soluciones integradas para crear y administrar varios subprocesos, pero ninguno de ellos es particularmente fácil de implementar, y pueden resultar en un código complejo y detallado que es difícil de leer y propenso a errores..

En RxJava, usted crea y administra subprocesos adicionales utilizando una combinación de operadores y planificadores. Puede cambiar fácilmente el hilo donde se realiza el trabajo, utilizando el suscribirseEn operador más un programador. Por ejemplo, aquí estamos programando el trabajo que se realizará en un nuevo hilo:

.subscribeOn (Schedulers.newThread ())

Puede especificar dónde deben publicarse los resultados de este trabajo, utilizando el observar operador. Aquí, estamos publicando los resultados en el importante subproceso de la interfaz de usuario principal de Android, usando el AndroidSchedulers.mainThread planificador, que está disponible como parte de la biblioteca RxAndroid:

.observeOn (AndroidSchedulers.mainThread ())

En comparación con las soluciones de subprocesamiento múltiple incorporadas en Android, el enfoque de RxJava es mucho más conciso y fácil de entender.

Una vez más, puede obtener más información sobre cómo funciona RxJava y los beneficios de agregar esta biblioteca a su proyecto en mi artículo de Comenzar con RxJava 2 para Android.

¿Debería estar utilizando RxJava o RxKotlin?

Como Kotlin es 100% interoperable con Java, puede usar la mayoría de las bibliotecas de Java en sus proyectos de Kotlin sin ninguna dificultad, y la biblioteca RxJava no es una excepción..

Ahí es una biblioteca dedicada de RxKotlin, que es un contenedor de Kotlin alrededor de la biblioteca RxJava normal. Esta envoltura proporciona extensiones que optimizan RxJava para el entorno Kotlin y puede reducir aún más la cantidad de código de boilerplate que necesita escribir.

Ya que puedes usar RxJava en Kotlin sin necesidad de RxKotlin, usaremos RxJava en este artículo, a menos que se indique lo contrario..

Creando observadores simples y observables en Kotlin

Los observadores y los observables son los componentes básicos de RxJava, así que comencemos creando:

  • Un observable simple que emite un breve flujo de datos en respuesta a un evento de clic de botón.
  • Un observable que reacciona a estos datos imprimiendo diferentes mensajes a Android Studio. Logcat.

Cree un nuevo proyecto con la configuración de su elección, pero asegúrese de seleccionar Incluye soporte de Kotlin. casilla de verificación cuando se le solicite. A continuación, abre tu proyecto construir.gradle Archivo y agregue la biblioteca RxJava como una dependencia de proyecto:

dependencias implementación fileTree (dir: 'libs', incluye: ['* .jar']) implementación "org.jetbrains.kotlin: kotlin-stdlib-jdk7: $ kotlin_version" implementación 'androidx.appcompat: appcompat: 1.0.0- alfa1 'implementación' androidx.constraintlayout: diseño de restricción: 1.1.0 'implementación' io.reactivex.rxjava2: rxjava: 2.1.9 '

Entonces, abre tu proyecto activity_main.xml Archivo y agregue el botón que iniciará el flujo de datos:

  

Hay varias formas diferentes de crear un Observable, pero una de las más fáciles es usar el sólo() operador para convertir un objeto o lista de objetos en un observable.

En el siguiente código, estamos creando un Observable (myObservable) y dándole los elementos 1, 2, 3, 4 y 5 para emitir. También estamos creando un observador (myObserver), suscribiéndolo a myObservable, y luego diciéndole que imprima un mensaje a Logcat Cada vez que recibe una nueva emisión..

import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.util.Log import io.reactivex.Observable import io.reactivex.Observer import io.reactivex.disposables.Disposable import kotlinx.android.synthetic. . * class MainActivity: AppCompatActivity () private var TAG = "MainActivity" reemplaza a fun onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Iniciar la transmisión cuando se hace clic en el botón // button.setOnClickListener startRStream () private fun startRStream () // Crear un Observable // val myObservable = getObservable () // Crear un Observer // val myObserver = getObserver () // Suscribir myObserver a myObservable / / myObservable .subscribe (myObserver) diversión privada getObserver (): Observer devolver objeto: observador override fun onSubscribe (d: Disposable)  // Cada vez que se llame onNext, imprima el valor en Logcat de Android Studio // override fun onNext (s: String) Log.d (TAG, "onNext: $ s")  // Llamado si se lanza una excepción // Reemplace la diversión onError (e: Throwable) Log.e (TAG, "onError:" + e.message) // Cuando se llama onComplete, imprima lo siguiente en Logcat // anular fun onComplete () Log.d (TAG, "onComplete") // Proporcionar a myObservable algunos datos para emitir // diversión privada getObservable (): observable return Observable.just ("1", "2", "3", "4", "5")

Ahora puedes poner esta aplicación a prueba:

  • Instale su proyecto en un teléfono o tableta física Android o en un dispositivo virtual Android (AVD).
  • Dar el Iniciar la transmisión de RxJava botón de un clic.
  • Abra el Monitor Logcat de Android Studio seleccionando Monitor de android pestaña (donde el cursor está posicionado en la siguiente captura de pantalla) y luego seleccionando Logcat lengüeta.

En este punto, el observable comenzará a emitir sus datos y el observador imprimirá sus mensajes a Logcat. Tu salida de Logcat debería verse así:

Puedes descargar este proyecto desde GitHub si quieres probarlo por ti mismo..

Extensiones Kotlin para RxJava

Ahora que hemos visto cómo configurar una tubería RxJava simple en Kotlin, veamos cómo se puede lograr esto en Menos código, usando las funciones de extensión de RxKotlin.

Para usar la biblioteca RxKotlin, debe agregarla como una dependencia de proyecto:

dependencias implementación fileTree (dir: 'libs', incluye: ['* .jar']) implementación "org.jetbrains.kotlin: kotlin-stdlib-jdk7: $ kotlin_version" implementación 'androidx.appcompat: appcompat: 1.0.0- alpha1 'implementación' androidx.constraintlayout: restricción de reproducción: 1.1.0 'implementación' io.reactivex.rxjava2: rxjava: 2.1.9 '// Agregue la siguiente // implementación' io.reactivex.rxjava2: rxkotlin: 2.2.0 '

En el siguiente ejemplo, estamos usando RxKotlin's toObservable () función de extensión para transformar una Lista en un observable. También estamos usando el subscribeBy () función de extensión, ya que nos permite construir un observador usando argumentos con nombre, lo que resulta en un código más claro.

import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import io.reactivex.rxkotlin.subscribeBy import io.reactivex.rxkotlin.toxbspot.activo_inclive. fun onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Inicia la secuencia cuando se hace clic en el botón // button.setOnClickListener startRStream () private fun startRStream ()  val list = listOf ("1", "2", "3", "4", "5") // Aplique la función de extensión toObservable () // list.toObservable () // Construya su Observer usando el subscribeBy ( ) función de extensión // .subscribeBy (onNext = println (it), onError = it.printStackTrace (), onComplete = println ("onComplete!"))

Aquí está la salida que debería ver:

Resolviendo el problema de ambigüedad SAM de RxJava

RxKotlin también proporciona una solución importante para el problema de conversión de SAM que puede ocurrir cuando hay múltiples sobrecargas de parámetros de SAM en un método Java determinado. Esta ambigüedad de SAM confunde el compilador Kotlin, ya que no puede determinar qué interfaz se supone que debe convertir, y su proyecto no se compilará como resultado.

Esta ambigüedad de SAM es un problema particular cuando se utiliza RxJava 2.0 con Kotlin, ya que muchos de los operadores de RxJava toman varios tipos compatibles con SAM.

Veamos el problema de conversión de SAM en acción. En el siguiente código, estamos usando el cremallera() Operador para combinar la salida de dos observables:  

import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import io.reactivex.Observable import kotlinx.android.synthetic.main.activity_main. * class MainActivity: AppCompatActivity () fun overCreate (createdInstanceState: Bundle) .onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Inicia la secuencia cuando se hace clic en el botón // button.setOnClickListener startRStream () diversión privada startRStream () val numbers = Observable.range (1, 6 ) cadenas de valores = Observable.just ("One", "Two", "Three", "Four", "Five", "Six") val zipped = Observable.zip (cadenas, números) s, n -> " $ s $ n " zipped.subscribe (:: println)

Esto hará que el compilador de Kotlin arroje un error de inferencia de tipo. Sin embargo, RxKotlin proporciona métodos de ayuda y funciones de extensión para los operadores afectados, incluyendo Observables.zip (), que estamos usando en el siguiente código:

import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import io.reactivex.Observable import io.reactivex.rxkotlin.Observables import kotlinx.android.synthetic.main.activity_main. * class MainActivity: Comp (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Iniciar el flujo cuando se hace clic en el botón // button.setOnClickListener startRStream () private fun startRStream ()  = Observable.range (1, 6) cadenas de val = Observable.just ("One", "Two", "Three", "Four", "Five", "Six") val zipped = Observables.zip (cadenas, números ) s, n -> "$ s $ n" zipped.subscribe (:: println)

Aquí está la salida de este código:

Conclusión

En este tutorial, le mostré cómo comenzar a usar la biblioteca RxJava en sus proyectos de Kotlin, incluido el uso de una serie de bibliotecas adicionales de soporte, como RxKotlin y RxBinding. Analizamos cómo se pueden crear observadores y observables simples en Kotlin, hasta la optimización de RxJava para la plataforma Kotlin, utilizando funciones de extensión..

Hasta ahora, hemos utilizado RxJava para crear observables simples que emiten datos y observadores que imprimen estos datos en Logcat de Android Studio, pero no es así como usará RxJava en el mundo real.!

En la próxima publicación, veremos cómo RxJava puede ayudar a resolver los problemas del mundo real que encontrará al desarrollar aplicaciones de Android. Usaremos RxJava con Kotlin para crear un clásico Regístrate pantalla.