RxJava 2.0 es una popular biblioteca de programación reactiva que ha ayudado a innumerables desarrolladores de Android a crear aplicaciones altamente sensibles, usando menos código y menos complejidad., especialmente Cuando se trata de gestionar múltiples hilos.
Si eres uno de los muchos desarrolladores que ha hecho el cambio a Kotlin, entonces no significa que debas renunciar a RxJava.!
En la primera parte de esta serie, te mostré cómo pasar de la programación con RxJava 2.0 en Java a la programación con RxJava en Kotlin. También vimos cómo eliminar las repeticiones de sus proyectos aprovechando las funciones de extensión de RxKotlin y el secreto para evitar el problema de conversión de SAM que muchos desarrolladores encuentran cuando comienzan a usar RxJava 2.0 con Kotlin..
En esta segunda entrega, nos concentraremos en cómo RxJava puede ayudar a resolver los problemas que encontrará en los proyectos de Android de la vida real, mediante la creación de una aplicación reactiva de Android utilizando RxJava 2.0, RxAndroid y RxBinding..
En nuestro artículo de Programación reactiva con RxJava y RxKotlin, creamos algunas Observables
y Observadores
que imprimen datos a Android Studio's Logcat-Pero no es así como usarás RxJava en el mundo real..
En este artículo, te mostraré cómo usar RxJava para crear una pantalla que se usa en innumerables aplicaciones de Android: el clásico Regístrate pantalla.
Si tu aplicación tiene alguna tipo de experiencia de registro, por lo general, tendrá reglas estrictas sobre el tipo de información que acepta. Por ejemplo, tal vez la contraseña deba exceder un cierto número de caracteres, o la dirección de correo electrónico debe estar en un formato de correo electrónico válido.
Mientras tu podría compruebe la entrada del usuario una vez que llegan a la Regístrate Botón, esta no es la mejor experiencia de usuario, ya que los deja abiertos para enviar información que claramente nunca será aceptada por su aplicación..
Es mucho mejor monitorear a los usuarios mientras escriben, y luego avisarles tan pronto como quede claro que ingresan información que no cumple con los requisitos de su aplicación. Al proporcionar este tipo de comentarios en vivo y en curso, le da al usuario la oportunidad de corregir sus errores antes de golpeando eso Regístrate botón.
Mientras tu podría Supervisamos la actividad del usuario usando vanilla Kotlin. Podemos ofrecer esta funcionalidad usando mucho menos código al solicitar la ayuda de RxJava, además de algunas otras bibliotecas relacionadas..
Empecemos por construir nuestra interfaz de usuario. Voy a añadir lo siguiente:
EditTexts
, donde el usuario puede introducir su dirección de correo electrónico (ingrese correo electrónico
) y contraseña (introducir la contraseña
).TextInputLayout
envoltorios, que rodearán nuestra ingrese correo electrónico
y introducir la contraseña
EditTexts
. Estos envoltorios mostrarán una advertencia cada vez que el usuario ingrese una dirección de correo electrónico o contraseña que no cumpla con los requisitos de nuestra aplicación.Aquí está mi diseño terminado:
Si lo desea, puede copiar / pegar esto en su aplicación, o simplemente puede descargar el código fuente del proyecto desde nuestro repositorio de GitHub.
Ahora veamos cómo podemos usar RxJava, más algunas bibliotecas relacionadas, para monitorear las opiniones de los usuarios y proporcionar comentarios en tiempo real.
Estaré abordando el Regístrate Pantalla en dos partes. En la primera sección, le mostraré cómo usar la biblioteca RxBinding para registrarse y responder a eventos de cambio de texto. En la segunda sección, crearemos algunas funciones de transformación que validan la entrada del usuario y luego mostraremos un mensaje de error cuando corresponda..
Cree un nuevo proyecto con la configuración de su elección, pero cuando se le solicite, asegúrese de seleccionar Incluir soporte de Kotlin caja.
En esta sección, implementaremos la siguiente funcionalidad:
ingrese correo electrónico
campo.tostada
. RxBinding es una biblioteca que facilita la conversión de una amplia gama de eventos de IU en Observables, en cuyo punto puede tratarlos como cualquier otro flujo de datos RxJava..
Vamos a monitorear eventos de cambio de texto, combinando RxBinding widget.RxTextView
con el afterTextChangeEvents
método, por ejemplo:
RxTextView.afterTextChangeEvents (enterEmail)
El problema con el tratamiento de eventos de cambio de texto como flujos de datos es que inicialmente ambos ingrese correo electrónico
y enterPassword EditTexts
estará vacío y no queremos que nuestra aplicación reaccione a este estado vacío como si fuera la primera emisión de datos en el flujo. RxBinding resuelve este problema proporcionando un skipInitialValue ()
Método, que utilizaremos para indicar a cada observador que ignore el valor inicial de su transmisión..
RxTextView.afterTextChangeEvents (enterEmail) .skipInitialValue ()
Miro la biblioteca RxBinding con mayor detalle en mi artículo de RxJava 2 para aplicaciones de Android.
.rebotar ()
OperadorPara ofrecer la mejor experiencia de usuario, debemos mostrar cualquier contraseña o advertencia de correo electrónico relevante después de que el usuario haya terminado de escribir, pero antes de que lleguen a la Regístrate botón.
Sin RxJava, la identificación de esta estrecha ventana de tiempo normalmente nos obligaría a implementar un Minutero
, Pero en RxJava solo tenemos que aplicar el rebotar ()
Operador a nuestro flujo de datos.
Voy a usar el rebotar ()
operador para filtrar todos los eventos de cambio de texto que suceden en una sucesión rápida, es decir, cuando el usuario todavía está escribiendo. Aquí, ignoramos todos los eventos de cambio de texto que ocurren dentro de la misma ventana de 400 milisegundos:
RxTextView.afterTextChangeEvents (enterEmail) .skipInitialValue () .debounce (400, TimeUnit.MILLISECONDS)
AndroidSchedulers.mainThread ()
La biblioteca de RxAndroid AndroidSchedulers.mainThread
nos da una manera fácil de cambiar al importante subproceso de la interfaz de usuario principal de Android.
Ya que solo es posible actualizar la interfaz de usuario de Android desde el subproceso principal de la interfaz de usuario, debemos asegurarnos de que estamos en este hilo antes de intentar mostrar cualquier correo electrónico o advertencias de contraseña, y antes de mostrar nuestra tostada
.
RxTextView.afterTextChangeEvents (enterEmail) .skipInitialValue () .debounce (400, TimeUnit.MILLISECONDS) .observeOn (AndroidSchedulers.mainThread ())
Para recibir los datos emitidos por ingrese correo electrónico
, Necesitamos suscribirlo:
RxTextView.afterTextChangeEvents (enterEmail) .skipInitialValue () .debounce (400, TimeUnit.MILLISECONDS) .observeOn (AndroidSchedulers.mainThread ()) .subscribe
Eventualmente, queremos que nuestra aplicación responda a eventos de cambio de texto mediante la validación de la entrada del usuario, pero para ayudar a mantener las cosas claras, en este punto simplemente voy a mostrar una tostada
.
Su código debe verse algo como esto:
import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.widget.Toast import com.jakewharton.rxbinding2.widget.RxTextView import kotlinx.android.synthetic.main.activity_main. * import io.reactivex.android .schedulers.AndroidSchedulers import java.util.concurrent.TimeUnit class MainActivity: AppCompatActivity () override fun onCreate (savedInstance. skipInitialValue () .debounce (400, TimeUnit.MILLISECONDS) .observeOn (AndroidSchedulers.mainThread ()) .subscribe Toast.makeText ("400 milisegundos desde el último cambio de texto", Toast.LENGTH_SHORT) .show)))
Ya que estamos usando algunas bibliotecas diferentes, necesitamos abrir nuestro proyecto construir.gradle presentar y agregar RxJava, RxBinding y RxAndroid como dependencias del proyecto:
dependencias implementación fileTree (dir: 'libs', incluye: ['* .jar']) implementación "org.jetbrains.kotlin: kotlin-stdlib-jdk7: $ kotlin_version" implementación 'com.android.support:design:28.0. 0-alpha1 'implementación' com.android.support:appcompat-v7:28.0.0-alpha1 'implementación' com.android.support.constraint: diseño de restricción: 1.1.0 '// Agregar la dependencia RxJava // implementación' io.reactivex.rxjava2: rxjava: 2.1.9 '// Agregar la dependencia de RxAndroid // implementación' io.reactivex.rxjava2: rxandroid: 2.0.2 '// Agregar la dependencia de RxBinding // implementación' com.jakewharton.rxbinding2: rxbinding: 2.1.1 '
Puede probar esta parte de su proyecto instalándola en su teléfono o tableta física Android o dispositivo virtual Android (AVD). Selecciona el ingrese correo electrónico
Editar texto
y empieza a escribir; una tostada
debe aparecer cuando dejas de escribir.
A continuación, debemos establecer algunas reglas básicas sobre el tipo de entrada que aceptará nuestra aplicación, y luego comparar la entrada del usuario con estos criterios y mostrar un mensaje de error cuando corresponda..
La verificación del correo electrónico o la contraseña del usuario es un proceso de varios pasos, por lo que para hacer que nuestro código sea más fácil de leer, voy a combinar todos estos pasos en su propio función de transformación.
Aquí está el comienzo de la validar correo electrónico
función de transformación:
// Definir un observableTransformer. La entrada y la salida deben ser una cadena // private val validateEmailAddress = ObservableTransformerobservable -> // Use flatMap para aplicar una función a cada elemento emitido por el Observable // observable.flatMap // Recorte cualquier espacio en blanco al principio y al final de la entrada del usuario // Observable.just (it) .map it.trim () // Comprueba si la entrada coincide con el patrón de correo electrónico de Android // .filter Patterns.EMAIL_ADDRESS.matcher (it) .matches ()
En el código anterior, estamos usando el filtrar()
operador para filtrar la salida del Observable en función de si coincide con Android Patrones.EMAIL_ADDRESS
modelo.
En la siguiente parte de la función de transformación, debemos especificar qué sucede si la entrada no coincide con la DIRECCIÓN DE CORREO ELECTRÓNICO
modelo. Por defecto, cada error irrecuperable activará una llamada a onError ()
, que termina el flujo de datos. En lugar de terminar la transmisión, queremos que nuestra aplicación muestre un mensaje de error, así que voy a usar onErrorResumeNext
, que indica al observable que responda a un error al pasar el control a un nuevo observable, en lugar de invocar onError ()
. Esto nos permite mostrar nuestro mensaje de error personalizado.
// Si la entrada del usuario no coincide con el patrón de correo electrónico, arroje un error // .singleOrError () .onErrorResumeNext if (es NoSuchElementException) Single.error (Exception ("Por favor, ingrese una dirección de correo electrónico válida")) else Single.error (it) .toObservable ()
El último paso es aplicar esta función de transformación a la secuencia de datos del correo electrónico, utilizando el .componer()
operador. En este punto, tu MainActivity.kt Debería verse algo como esto:
import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.util.Patterns import io.reactivex.Observable import io.reactivex.ObservableTransformer. import kotlinx.android.synthetic.main.activity_main. * import java.util.concurrent.TimeUnit import com.jakewharton.rxbinding2.widget.RxTextView class MainActivity: (savedInstanceState) setContentView (R.layout.activity_main) RxTextView.afterTextChangeEvents (enterEmail) .skipInitialValue () .map emailError.error = null it.view (). text.toString () .debounce (400, // estamos en el hilo principal de la IU de Android // TimeUnit.MILLISECONDS) .observeOn (AndroidSchedulers.mainThread ()) .compose (validateEmailAddress) .pose (retryWhenError passwordError.error = it.message)) .subscribe () // If la aplicación encuentra un error, luego vuelva a intentarlo // private inline fu n retryWhenError (crossinline onError: (ej: Throwable) -> Unit): ObservableTransformer= ObservableTransformer observable -> observable.retryWhen errors -> // Use el operador flatmap () para acoplar todas las emisiones en un solo Observable // errors.flatMap onError (it) Observable.just ("") / / Defina un ObservableTransformer, donde realizaremos la validación de correo electrónico // private val validateEmailAddress = ObservableTransformer observable -> observable.flatMap Observable.just (it) .map it.trim () // Verifique si la entrada del usuario coincide con el patrón de correo electrónico de Android // .filter Patterns.EMAIL_ADDRESS.matcher (it) .matches ( ) // Si la entrada del usuario no coincide con el patrón de correo electrónico, arroje un error // .singleOrError () .onErrorResumeNext if (es NoSuchElementException) Single.error (Exception ("Por favor, ingrese una dirección de correo electrónico válida" )) else Single.error (it) .toObservable ()
Instale este proyecto en su dispositivo Android o AVD, y encontrará que la parte del correo electrónico de la Regístrate La pantalla ahora está revisando su entrada con éxito. Intente ingresar algo que no sea una dirección de correo electrónico, y la aplicación le advertirá que esto no es una entrada válida.
En este punto, tenemos un funcionamiento pleno ingrese correo electrónico
campo e implementación introducir la contraseña
Es sobre todo solo un caso de repetir los mismos pasos..
De hecho, la única gran diferencia es que nuestra validatePassword
La función de transformación necesita verificar diferentes criterios. Especificaré que la entrada de la contraseña del usuario debe tener al menos 7 caracteres:
.filtro it.length> 7
Después de repetir todos los pasos anteriores, el MainActivity.kt Debería verse algo como esto:
import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.util.Patterns import io.reactivex.Observable import io.reactivex.ObservableTransformer. import kotlinx.android.synthetic.main.activity_main. * import java.util.concurrent.TimeUnit import com.jakewharton.rxbinding2.widget.RxTextView class MainActivity: Comp Comp (savedInstanceState) setContentView (R.layout.activity_main) // Responde a los eventos de cambio de texto en enterEmail // RxTextView.afterTextChangeEvents (enterEmail) // Skip enterInmail inicial, empty state // .skipInitialValue () // Transforma los datos que se emiten / / .map emailError.error = nulo // Convierta la entrada del usuario en una Cadena // it.view (). text.toString () // Ignore todas las emisiones que ocurren dentro de un lapso de tiempo de 400 milisegundos // .debounce (400 , // Asegúrate de que estamos en el hilo principal de la interfaz de usuario de Android // Tim eUnit.MILLISECONDS) .observeOn (AndroidSchedulers.mainThread ()) // Aplique la función de transformación validateEmailAddress // .compose (validateEmailAddress) // Aplique la función de transformación retryWhenError // //posepose (retryWhenError email.ror.error = it.message) it) .subscribe () // Enjuague y repita para enterPassword EditText // RxTextView.afterTextChangeEvents (enterPassword) .skipInitialValue () .map passwordError.error = null it.view (). text.toString () .debounce (400, TimeUnit.MILLISECONDS) .observeOn (AndroidSchedulers.mainThread ()) .compose (validatePassword) .compose (retryWhenError passwordError.error = it.message) .subscribe () // Si la aplicación encuentra un error, vuelva a intentarlo / / reintento de diversión en línea privadoWhenError (crossinline onError: (ej: Throwable) -> Unit): ObservableTransformer= ObservableTransformer observable -> observable.retryWhen errors -> /// Use el operador flatmap () para acoplar todas las emisiones en un solo Observable // errors.flatMap onError (it) Observable.just ("") // Defina nuestro ObservableTransformer y especifique que la entrada y la salida deben ser una cadena // private val validatePassword = ObservableTransformer observable -> observable.flatMap Observable.just (it) .map it.trim () // Permitir solo contraseñas de al menos 7 caracteres // .filter it.length> 7 // Si el la contraseña tiene menos de 7 caracteres, luego lance un error // .singleOrError () // Si ocurre un error ... // .onErrorResumeNext if (es NoSuchElementException) // Muestra el siguiente mensaje en la contraseñaError TextInputLayout // Single. error (Excepción ("Su contraseña debe tener 7 caracteres o más")) else Single.error (it) .toObservable () // Define un ObservableTransformer, donde realizaremos la validación de correo electrónico // privado val validateEmailAddress = ObservableTransformer observable -> observable.flatMap Observable.just (it) .map it.trim () // Verifique si la entrada del usuario coincide con el patrón de correo electrónico de Android // .filter Patterns.EMAIL_ADDRESS.matcher (it) .matches ( ) // Si la entrada del usuario no coincide con el patrón de correo electrónico ... // .singleOrError () .onErrorResumeNext if (es NoSuchElementException) //// Muestra el siguiente mensaje en el correo electrónicoError TextInputLayout // Single.error ( Excepción ("Ingrese una dirección de correo electrónico válida")) else Single.error (it) .toObservable ()
Instale este proyecto en su dispositivo Android o AVD, y experimente tecleando en el ingrese correo electrónico
y introducir la contraseña
campos. Si ingresa un valor que no cumple con los requisitos de la aplicación, se mostrará el mensaje de advertencia correspondiente, sin tienes que tocar el Regístrate botón.
Puedes descargar este proyecto completo desde GitHub..
En este artículo, vimos cómo RxJava puede ayudar a resolver los problemas del mundo real que encontrará al desarrollar sus propias aplicaciones de Android, utilizando RxJava 2.0, RxBinding y RxAndroid para crear un Regístrate pantalla.
Para obtener más información de fondo sobre la biblioteca RxJava, asegúrese de consultar nuestro artículo Comenzar con RxJava 2.0.