Programación Reactiva Kotlin con RxJava y RxKotlin
() translation by (you can also view the original English article)
Desde que es un lenguaje de apoyo oficial para el desarrollo de Android, Kotlin ha crecido rápidamente en popularidad entre los desarrolladores de Android, Google reporte un aumento de 6x en las aplicaciones que se crean mediante Kotlin.
Si anteriormente has usado RxJava o RxAndroid y quiere hacer el cambio a Kotlin, o desea iniciar reactiva con Kotlin, este tutorial es para ti. Cubriremos los fundamentos de crear flujos de datos, Observables
y RxJava 2.0 observadores
en Kotlin, antes de mirar cómo puede recortar una tonelada de código repetitivo de sus proyectos, combinando RxJava con funciones de extensión de Kotlin.
Usando RxJava con Kotlin puede ayudarle a crear aplicaciones altamente reactivos en menos código, pero no hay lenguaje de programación es perfecta, así que voy a compartir también una solución para el problema de la conversión de SAM que muchos desarrolladores cuando empiece a usar RxJava 2.0 con Kotlin .
Para envolver cosas para arriba, vamos a crear una aplicación que muestra cómo puede utilizar RxJava para resolver algunos de los temas que encuentras en la vida real proyectos Android.
Si este es su primer gusto de RxJava, luego en el camino voy también proporcionar todos los antecedentes que necesita para entender los conceptos básicos de RxJava. Incluso si nunca has experimentado con RxJava antes, al final de este artículo usted tendrá una comprensión sólida de cómo usar esta biblioteca en sus proyectos, y habrá creado varias aplicaciones de trabajo, con RxJava, RxKotlin, RxAndroid y RxBinding.
¿Qué es RxJava, de Todos Modos?
RxJava es una implementación open-source de la librería ReactiveX que le ayuda a crear aplicaciones en el estilo de programación reactivo. Aunque RxJava está diseñado para procesar flujos sincrónicas y asincrónicas de datos, no se restringe a tipos de datos "tradicional". Definición de RxJava de "datos" es bastante amplio e incluye cosas como escondites, variables, propiedades y aun usuario eventos de entrada como clics y golpes fuertes. Simplemente porque su aplicación no tratar con números grandes o realizar transformaciones de datos complejos, no significa que no pueden beneficiarse de RxJava!
Para un poco de historia sobre el uso de RxJava para aplicaciones de Android, usted puede consultar algunos de mis otros posts aquí en Envato Tuts+.
- SDK de AndroidEmpezar con RxJava 2 para AndroidJessica Thornsby
- SDK de AndroidRxJava 2 para Android Apps: RxBinding y RxLifecycleJessica Thornsby
¿Cómo Funciona RxJava?
RxJava extiende el patrón de diseño Observer software, que se basa en el concepto de observadores y Observables. Para crear una tubería de datos básica de RxJava, es necesario:
- Crear un Observable.
- Dar el Observable de algunos datos a emitir.
- Crear un observador.
- Suscribirse al observador el Observable.
Tan pronto como el Observable tiene al menos un observador, comenzará a emitir datos. Cada vez el Observable emite un dato, lo voy a su observador asignado llamando al método onNext()
, y el observador entonces típicamente realizará alguna acción en respuesta a esta emisión de datos. Una vez que el Observable ha terminado de emitir datos, te notificar al observador llamando al onComplete()
. El Observable entonces se terminará, y pondrá fin a la secuencia de datos.
Si se produce una excepción, entonces se llamará onError()
y el Observable terminará inmediatamente sin emitir más datos o llamando al onComplete()
.
Pero RxJava casi no es pasar datos de un Observable a un observador. RxJava tiene una colección enorme de operadores que puede utilizar para filtrar, combinar y transformar estos datos. Por ejemplo, imagine que su aplicación tiene un botón Pagar Ahora que detecta eventos onClick
, y usted está preocupado de que un usuario impaciente podría Pulse el botón varias veces, haciendo que su aplicación procesar pagos varios.
RxJava le permite transformar estos eventos onClick
en una secuencia de datos, que luego se puede manipular con diferentes operadores de RxJava. En este ejemplo en concreto, puede utilizar el operador de debounce()
para filtrar las emisiones de datos que ocurren en rápida sucesión, por lo que incluso si el usuario se da en el botón de Pagar Ahora, su aplicación sólo registrará un solo pago.
¿Cuáles Son los Beneficios de Usar RxJava?
¿Hemos visto cómo RxJava puede ayudarle a resolver un problema específico, en una aplicación específica, pero lo que pueden ofrecer proyectos de Android, en general?
RxJava puede ayudar a simplificar el código que le da una forma de escribir lo que quieres lograr, en lugar de una lista de instrucciones que su aplicación tiene que trabajar a través de la escritura. Por ejemplo, si desea ignorar todas las emisiones de datos que ocurren dentro del mismo periodo de 500 milisegundos, entonces debería escribir:
1 |
.debounce(500, TimeUnit.MILLISECONDS) |
Además, ya que RxJava casi todo trata como datos, proporciona una plantilla que se puede aplicar a una amplia gama de eventos: crear un Observable, crear un observador, suscribirse al observador el Observable, enjuague y repita. Este enfoque formulista genera código mucho más sencillo, legible.
El otro gran beneficio para los desarrolladores de Android es que RxJava puede tomar gran parte del dolor de multithreading en Android. Los usuarios de hoy esperan que sus aplicaciones para poder realizar múltiples tareas, incluso si es algo tan sencillo como descargar los datos en segundo plano sin dejar de ser sensible a la entrada del usuario.
Android tiene varias soluciones integradas para crear y administrar múltiples hilos, pero ninguno de estos son particularmente fácil de aplicar, y rápidamente pueden resultar en código complejo y detallado que es difícil de leer y propenso a errores.
En RxJava, puede crea y administrar subprocesos adicionales mediante una combinación de operadores y programadores. Usted puede cambiar fácilmente el hilo donde se realiza el trabajo, usando el operador de subscribeOn
más un programador. Por ejemplo, aquí nos estamos programación de trabajos a realizar en un nuevo hilo:
1 |
.subscribeOn(Schedulers.newThread()) |
Puede especificar que los resultados de este trabajo deben ser publicada, utilizando el operador observeOn
. Aquí, estamos publicando los resultados a hilo importante de interfaz de usuario principal de Android, utilizando el programador de AndroidSchedulers.mainThread
, que está disponible como parte de la biblioteca de RxAndroid:
1 |
.observeOn(AndroidSchedulers.mainThread()) |
En comparación con incorporadas soluciones multithreading Android, enfoque de RxJava es mucho más conciso y fácil de entender.
Una vez más, puede aprender más sobre cómo funciona la RxJava y los beneficios de agregar esta librería a su proyecto, en mi artículo Haz Iniciado Con RxJava 2 para Android.
¿Debo Estar Usando RxJava o RxKotlin?
Kotlin es 100% interoperables con Java, puede utilizar la mayoría de las bibliotecas de Java en sus proyectos de Kotlin sin dificultad, y la biblioteca de RxJava no es una excepción.
Hay una biblioteca dedicada de RxKotlin, que es un contenedor de Kotlin alrededor de la biblioteca de RxJava regular. Esta envoltura proporciona extensiones que optimicen la RxJava para el entorno de Kotlin y pueden reducir la cantidad de código repetitivo, necesita escribir.
Puesto que usted puede utilizar RxJava en Kotlin sin necesidad alguna vez de RxKotlin, usaremos RxJava a lo largo de este artículo, a menos que se indique lo contrario.
Creación de Simples Observadores y Observables en Kotlin
Observadores y Observables son los bloques de edificio de RxJava, así que vamos a empezar por crear:
- Un simple Observable que emite un breve flujo de datos en respuesta a un evento de clic de botón.
- Un Observable que reacciona a estos datos mediante la impresión de mensajes diferentes a Android Studio Logcat.
Cree un nuevo proyecto con la configuración de su elección, pero asegúrese de que la casilla Incluir Kotlin apoyo cuando se le solicite. A continuación, abra el archivo del proyecto build.gradle y agregar a la biblioteca de RxJava como una dependencia de proyectos:
1 |
dependencies { |
2 |
implementation fileTree(dir: 'libs', include: ['*.jar']) |
3 |
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" |
4 |
implementation 'androidx.appcompat:appcompat:1.0.0-alpha1' |
5 |
implementation 'androidx.constraintlayout:constraintlayout:1.1.0' |
6 |
implementation 'io.reactivex.rxjava2:rxjava:2.1.9' |
7 |
|
8 |
} |
A continuación, abra el archivo del proyecto activity_main.xml y añadir el botón que comenzará la secuencia de datos:
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
3 |
xmlns:tools="http://schemas.android.com/tools" |
4 |
android:layout_width="match_parent" |
5 |
android:layout_height="match_parent" |
6 |
android:orientation="vertical" |
7 |
tools:context=".MainActivity" > |
8 |
|
9 |
<Button
|
10 |
android:id="@+id/button" |
11 |
android:layout_width="wrap_content" |
12 |
android:layout_height="wrap_content" |
13 |
android:text="Start RxJava stream" /> |
14 |
|
15 |
</LinearLayout>
|
Hay varias maneras diferentes de crear un Observable, pero uno de lo más fácil es usar el operador just()
para convertir un objeto o una lista de objetos en un Observable.
En el siguiente código, estamos creando un Observable (myObservable
) y lo que le confiere los artículos 1, 2, 3, 4 y 5 para emitir. También estamos creando un observador (myObserver
), suscripción a myObservable
y luego contarla para imprimir un mensaje a Logcat cada vez que recibe una nueva emisión.
1 |
import androidx.appcompat.app.AppCompatActivity |
2 |
import android.os.Bundle |
3 |
import android.util.Log |
4 |
import io.reactivex.Observable |
5 |
import io.reactivex.Observer |
6 |
import io.reactivex.disposables.Disposable |
7 |
import kotlinx.android.synthetic.main.activity_main.* |
8 |
|
9 |
class MainActivity : AppCompatActivity() { |
10 |
|
11 |
private var TAG = "MainActivity" |
12 |
|
13 |
override fun onCreate(savedInstanceState: Bundle?) { |
14 |
super.onCreate(savedInstanceState) |
15 |
setContentView(R.layout.activity_main) |
16 |
|
17 |
//Start the stream when the button is clicked//
|
18 |
|
19 |
button.setOnClickListener { startRStream() } |
20 |
|
21 |
}
|
22 |
|
23 |
private fun startRStream() { |
24 |
|
25 |
//Create an Observable//
|
26 |
|
27 |
val myObservable = getObservable() |
28 |
|
29 |
//Create an Observer//
|
30 |
|
31 |
val myObserver = getObserver() |
32 |
|
33 |
//Subscribe myObserver to myObservable//
|
34 |
|
35 |
myObservable
|
36 |
.subscribe(myObserver) |
37 |
}
|
38 |
|
39 |
private fun getObserver(): Observer<String> { |
40 |
return object : Observer<String> { |
41 |
override fun onSubscribe(d: Disposable) { |
42 |
}
|
43 |
|
44 |
//Every time onNext is called, print the value to Android Studio’s Logcat//
|
45 |
|
46 |
override fun onNext(s: String) { |
47 |
Log.d(TAG, "onNext: $s") |
48 |
}
|
49 |
|
50 |
//Called if an exception is thrown//
|
51 |
|
52 |
override fun onError(e: Throwable) { |
53 |
Log.e(TAG, "onError: " + e.message) |
54 |
}
|
55 |
|
56 |
//When onComplete is called, print the following to Logcat//
|
57 |
|
58 |
override fun onComplete() { |
59 |
Log.d(TAG, "onComplete") |
60 |
}
|
61 |
}
|
62 |
}
|
63 |
|
64 |
//Give myObservable some data to emit//
|
65 |
|
66 |
private fun getObservable(): Observable<String> { |
67 |
return Observable.just("1", "2", "3", "4", "5") |
68 |
}
|
69 |
}
|
Ahora usted puede poner esta aplicación a la prueba:
- Instalar su proyecto en un físico smartphone Android o tablet o un dispositivo Virtual Android (AVD).
- Darle al click al botón de Secuencia de Inicio RxJava.
- Abrir a Monitor de Logcat Android Studio seleccionando la pestaña de Monitor Android (donde se coloca el cursor en la siguiente captura de pantalla) y seleccionando la ficha Logcat.
En este punto, el Observable comenzará emitiendo sus datos, y el observador mostrará sus mensajes a Logcat. Su salida de Logcat debería ser algo como esto:



Si quieres probar por ti mismo, puede descargar este proyecto en GitHub.
Kotlin Extensiones para RxJava
Ahora que hemos visto cómo configurar una simple tubería de RxJava de Kotlin, echemos un vistazo a cómo usted puede lograr esto en menos código, usando funciones de extensión de RxKotlin.
Para utilizar la biblioteca de RxKotlin, necesita agregarlo como una dependencia de proyectos:
1 |
dependencies { |
2 |
implementation fileTree(dir: 'libs', include: ['*.jar']) |
3 |
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" |
4 |
implementation 'androidx.appcompat:appcompat:1.0.0-alpha1' |
5 |
implementation 'androidx.constraintlayout:constraintlayout:1.1.0' |
6 |
implementation 'io.reactivex.rxjava2:rxjava:2.1.9' |
7 |
|
8 |
//Add the following// |
9 |
|
10 |
implementation 'io.reactivex.rxjava2:rxkotlin:2.2.0' |
11 |
|
12 |
} |
En el siguiente ejemplo, estamos usando función de extensión de toObservable()
de RxKotlin para transformar una Lista
en un Observable. También estamos utilizando la función de extensión de la subscribeBy()
, ya que nos permite construir un observador usando argumentos con nombre, que se traduce en código más claro.
1 |
import android.os.Bundle |
2 |
import androidx.appcompat.app.AppCompatActivity |
3 |
import io.reactivex.rxkotlin.subscribeBy |
4 |
import io.reactivex.rxkotlin.toObservable |
5 |
import kotlinx.android.synthetic.main.activity_main.* |
6 |
|
7 |
class MainActivity : AppCompatActivity() { |
8 |
|
9 |
override fun onCreate(savedInstanceState: Bundle?) { |
10 |
super.onCreate(savedInstanceState) |
11 |
setContentView(R.layout.activity_main) |
12 |
|
13 |
//Start the stream when the button is clicked//
|
14 |
|
15 |
button.setOnClickListener { startRStream() } |
16 |
|
17 |
}
|
18 |
|
19 |
private fun startRStream() { |
20 |
|
21 |
val list = listOf("1", "2", "3", "4", "5") |
22 |
|
23 |
//Apply the toObservable() extension function//
|
24 |
|
25 |
list.toObservable() |
26 |
|
27 |
//Construct your Observer using the subscribeBy() extension function//
|
28 |
|
29 |
.subscribeBy( |
30 |
|
31 |
onNext = { println(it) }, |
32 |
onError = { it.printStackTrace() }, |
33 |
onComplete = { println("onComplete!") } |
34 |
|
35 |
)
|
36 |
}
|
37 |
}
|
Aquí está la salida que debería ver:



Solucionar problema de ambigüedad de RxJava SAM
RxKotlin también proporciona una importante solución para la cuestión de la conversión de SAM que puede ocurrir cuando hay múltiples SAM sobrecargas de parámetro en un determinado método de Java. Esta ambigüedad de SAM confunde el compilador Kotlin, como no puede trabajar hacia fuera que se supone que para convertir, y su proyecto no se compila como resultado.
Esta ambigüedad de SAM es un problema particular cuando uso RxJava 2.0 con Kotlin, como muchos de los operadores de RxJava varios tipos de SAM-compatible.
Vamos a ver el problema de la conversión de SAM en acción. En el siguiente código, estamos utilizando el operador zip()
para combinar la salida de dos Observables:
1 |
import androidx.appcompat.app.AppCompatActivity |
2 |
import android.os.Bundle |
3 |
import io.reactivex.Observable |
4 |
import kotlinx.android.synthetic.main.activity_main.* |
5 |
|
6 |
class MainActivity : AppCompatActivity() { |
7 |
|
8 |
override fun onCreate(savedInstanceState: Bundle?) { |
9 |
super.onCreate(savedInstanceState) |
10 |
setContentView(R.layout.activity_main) |
11 |
|
12 |
//Start the stream when the button is clicked//
|
13 |
|
14 |
button.setOnClickListener { startRStream() } |
15 |
|
16 |
}
|
17 |
|
18 |
private fun startRStream() { |
19 |
|
20 |
val numbers = Observable.range(1, 6) |
21 |
|
22 |
val strings = Observable.just("One", "Two", "Three", |
23 |
|
24 |
"Four", "Five", "Six" ) |
25 |
|
26 |
val zipped = Observable.zip(strings, numbers) { s, n -> "$s $n" } |
27 |
zipped.subscribe(::println) |
28 |
}
|
29 |
}
|
Esto hará que el compilador de Kotlin a tirar un error de inferencia de tipos. Sin embargo, RxKotlin proporciona métodos y funciones de extensión para los operadores afectados, incluyendo Observables.zip()
, que estamos utilizando en el siguiente código:
1 |
import android.os.Bundle |
2 |
import androidx.appcompat.app.AppCompatActivity |
3 |
import io.reactivex.Observable |
4 |
import io.reactivex.rxkotlin.Observables |
5 |
import kotlinx.android.synthetic.main.activity_main.* |
6 |
|
7 |
class MainActivity : AppCompatActivity() { |
8 |
|
9 |
override fun onCreate(savedInstanceState: Bundle?) { |
10 |
super.onCreate(savedInstanceState) |
11 |
setContentView(R.layout.activity_main) |
12 |
|
13 |
//Start the stream when the button is clicked//
|
14 |
|
15 |
button.setOnClickListener { startRStream() } |
16 |
|
17 |
}
|
18 |
|
19 |
private fun startRStream() { |
20 |
|
21 |
val numbers = Observable.range(1, 6) |
22 |
|
23 |
val strings = Observable.just("One", "Two", "Three", |
24 |
|
25 |
"Four", "Five", "Six" ) |
26 |
|
27 |
val zipped = Observables.zip(strings, numbers) { s, n -> "$s $n" } |
28 |
zipped.subscribe(::println) |
29 |
}
|
30 |
|
31 |
|
32 |
}
|
Aquí está la salida de este código:



Conclusión
En este tutorial, mostró cómo comenzar a usar la biblioteca de RxJava en sus proyectos de Kotlin, incluyendo el uso de una serie de librerías apoyo adicionales, como RxKotlin y RxBinding. Vimos cómo crear simples observadores y Observables en Kotlin, pasando para la optimización de RxJava para la plataforma de Kotlin, usando funciones de extensión.
Hasta ahora, hemos utilizado RxJava para crear simples Observables que emiten datos y observadores que imprimir estos datos Logcat del estudio Android, pero esto no es como lo usas RxJava en el mundo real!
En el siguiente post, vamos a ver cómo RxJava puede ayudar a resolver problemas del mundo real que te vas a encontrar en el desarrollo de aplicaciones para Android. Usaremos RxJava con Kotlin crear una clásica pantalla para Registrarse.