Programación reactiva de Kotlin para una pantalla de registro de Android

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..

¿Cómo puedo usar RxJava en proyectos del mundo real??

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..

Creación de la interfaz de usuario

Empecemos por construir nuestra interfaz de usuario. Voy a añadir lo siguiente:

  • Dos EditTexts, donde el usuario puede introducir su dirección de correo electrónico (ingrese correo electrónico) y contraseña (introducir la contraseña).
  • Dos 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.
  • Un botón de visibilidad de contraseña, que permite al usuario alternar entre enmascarar la contraseña y verla como texto sin formato..
  • UNA Regístrate botón. Para ayudar a mantener este ejemplo enfocado en RxJava, no implementaré esta parte de la experiencia de registro, así que marcaré este botón como deshabilitado.

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.

Creación de una experiencia de inicio de sesión reactiva con Kotlin

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. 

Respondiendo a eventos de cambio de texto

En esta sección, implementaremos la siguiente funcionalidad: 

  • Detectar cuando el usuario está escribiendo en el ingrese correo electrónico campo.
  • Ignore todos los eventos de cambio de texto que ocurren dentro de un corto espacio de tiempo, ya que esto indica que el usuario todavía está escribiendo. 
  • Realizar una acción cuando el usuario deja de escribir. En nuestra aplicación terminada, aquí es donde validaremos la entrada del usuario, pero en esta sección solo mostraré un tostada

1. RxBinding 

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.

2. RxJava's .rebotar () Operador

Para 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)

3. RxAndroid's 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 ())

4. Suscribir

Para recibir los datos emitidos por ingrese correo electrónico, Necesitamos suscribirlo:

 RxTextView.afterTextChangeEvents (enterEmail) .skipInitialValue () .debounce (400, TimeUnit.MILLISECONDS) .observeOn (AndroidSchedulers.mainThread ()) .subscribe 

5. Mostrar la tostada

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)))

6. Actualice sus dependencias

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. 

Validar la entrada del usuario con funciones de transformación

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 = ObservableTransformer observable -> // 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. 

Enjuague y repita: Verifique la contraseña del usuario

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..

Conclusión

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.