RxJava 2 para aplicaciones de Android RxBinding y RxLifecycle

RxJava es una de las bibliotecas más populares para llevar la programación reactiva a la plataforma Android, y en esta serie de tres partes, le he estado mostrando cómo comenzar a usar esta biblioteca en sus propios proyectos con Android.

En Introducción a RxJava 2 para Android, analizamos qué es RxJava y lo que ofrece a los desarrolladores de Android, antes de crear una aplicación Hello World que demostrara los tres componentes principales de RxJava: un Observable, un Observador, y una suscripción.

En el tutorial de Operadores de programación reactiva en RxJava 2, observamos cómo realizar transformaciones de datos complejas utilizando operadores, y cómo puede combinar Operadors y Programadors para que finalmente el multihilo en Android sea una experiencia sin dolor.

También abordamos RxAndroid, una biblioteca diseñada específicamente para ayudarte a utilizar RxJava en tus proyectos de Android, pero hay mucho más que explorar en RxAndroid. Entonces, en este post, me centraré únicamente en la familia de bibliotecas RxAndroid.

Al igual que RxJava, RxAndroid se sometió a una revisión masiva en su versión 2. El equipo de RxAndroid decidió modularizar la biblioteca, trasladando gran parte de su funcionalidad a los módulos adicionales de RxAndroid dedicados.

En este artículo, le mostraré cómo configurar y usar algunos de los módulos RxAndroid más populares y potentes, incluida una biblioteca que puede hacer escuchas, controladores y Observadores de texto una cosa del pasado, dándote la capacidad de manejar alguna Evento de la interfaz de usuario de Android como Observable.

Y como las pérdidas de memoria causadas por suscripciones incompletas son el mayor inconveniente de usar RxJava en sus aplicaciones de Android, también le mostraré cómo usar un módulo RxAndroid que puede manejar el proceso de suscripción por usted. Al final de este artículo, sabrás cómo usar RxJava en cualquier Actividad o Fragmento, Sin correr el riesgo de encontrarse. alguna Fugas de memoria relacionadas con RxJava.

Creación de interfaces de usuario más reactivas para Android

Reaccionar a los eventos de la IU, como los toques, los golpes y la entrada de texto, es una parte fundamental del desarrollo de casi cualquier aplicación de Android, pero el manejo de los eventos de la IU de Android no es particularmente sencillo..

Por lo general, reaccionarás a los eventos de la interfaz de usuario utilizando una combinación de escuchas y controladores., Observadores de texto, y posiblemente otros componentes dependiendo del tipo de IU que esté creando. Cada uno de estos componentes requiere que usted escriba una cantidad significativa de código repetitivo, y para empeorar las cosas, no hay coherencia en la forma en que implementa estos diferentes componentes. Por ejemplo, manejas Al hacer clic eventos mediante la implementación de una OnClickListener:

Button button = (Button) findViewById (R.id.button); button.setOnClickListener (new View.OnClickListener () @Override public void onClick (View v) // Realizar algunos trabajos //);

Pero esto es completamente diferente a cómo implementarías un TextWatcher:

final EditText name = (EditText) v.findViewById (R.id.name); // Cree un TextWatcher y especifique que este TextWatcher debe llamarse cada vez que el contenido de EditText cambie // name.addTextChangedListener (new TextWatcher () @Override public void beforeTextChanged (CharSequence s, int start, int after, int after)  @ Anular el vacío público onTextChanged (CharSequence s, int start, int before, int count) // Realizar algún trabajo // @ Anular el void public void afterTextChanged (Editable s) );

Esta falta de coherencia puede potencialmente agregar mucha complejidad a su código. Y si tiene componentes de UI que dependen de la salida de otros componentes de UI, entonces prepárese para que las cosas se compliquen aún más. Incluso un caso de uso simple, como pedirle al usuario que escriba su nombre en un Editar texto Para que puedas personalizar el texto que aparece en las siguientes. Visiones de texto-requiere devoluciones de llamada anidadas, que son muy difíciles de implementar y mantener. (Algunas personas se refieren a devoluciones de llamada anidadas como "infierno de devolución de llamada").

Claramente, un enfoque estandarizado para el manejo de eventos de UI tiene el potencial de simplificar enormemente su código, y RxBinding es una biblioteca que se compromete a hacer precisamente eso, al proporcionar enlaces que le permiten convertir cualquier Android Ver evento en un Observable.  

Una vez que haya convertido un evento de visualización en un Observable, emitirá sus eventos de IU como flujos de datos a los que puede suscribirse exactamente de la misma manera que lo haría con cualquier otro Observable.

Ya hemos visto cómo capturarías un evento de clic con el estándar de Android OnClickListener, veamos cómo lograrías los mismos resultados usando RxBinding:

importar com.jakewharton.rxbinding.view.RxView;… Button button = (Button) findViewById (R.id.button); RxView.clicks (button) .subscribe (aVoid -> // Realice algunos trabajos aquí //);

Este enfoque no solo es más conciso, sino que es una implementación estándar que puede aplicar a todos los eventos de IU que se producen a lo largo de su aplicación. Por ejemplo, la captura de entrada de texto sigue el mismo patrón que la captura de eventos de clic:

RxTextView.textChanges (editText) .subscribe (charSequence -> // Realice algunos trabajos aquí //);

Una aplicación de ejemplo con RxBinding

Para que pueda ver exactamente cómo RxBinding puede simplificar el código relacionado con la interfaz de usuario de su aplicación, creemos una aplicación que demuestre algunos de estos enlaces en acción. También voy a incluir un Ver eso depende de la salida de otro Ver, para demostrar cómo RxBinding simplifica la creación de relaciones entre los componentes de la interfaz de usuario.

Esta aplicación va a consistir en:

  • UNA Botón que muestra un tostada cuando se toca.
  • Un Editar texto que detecta cambios de texto.
  • UNA Vista de texto que se actualiza para mostrar los contenidos de la Editar texto.

Configuración del proyecto

Cree un proyecto de Android Studio con la configuración de su elección y luego abra su nivel de módulo construir.gradle Archivo y agregue la última versión de la biblioteca RxBinding como una dependencia de proyecto. Con el fin de mantener el código de repetición al mínimo, también voy a utilizar lambdas, así que he actualizado mi construir.gradle Archivo para soportar esta característica de Java 8:

aplique el complemento: 'com.android.application' android compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig applicationId "com.jessicathornsby.myapplication" ".nal" "" ". AndroidJUnitRunner "// Habilitar la cadena de herramientas de Jack // jackOptions enabled true buildTypes release minifyEnabled false proguardFiles getDefaultProguardFile ('proguard-android.txt'), 'proguard-rules.pro' // Set sourceCompatibility and targetCompatibility to JavaVersion.VERSION_1_8 // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 dependencies compile fileTree (dir: 'libs', include: ['* .jar']) androidTestCompile ('com.android.support.estport) : espresso-core: 2.2.2 ', exclude group:' com.android.support ', módulo:' support-anotaciones ') // Agregue la biblioteca RxBinding central // compile' com.jakewharton.rxbinding: rxbinding: 0.4.0 'compilar' com .android.support: appcompat-v7: 25.3.0 '// No olvide agregar las dependencias RxJava y RxAndroid // compile' io.reactivex.rxjava2: rxandroid: 2.0.1 'compile' io.reactivex.rxjava2: rxjava: 2.0.5 'testCompile' junit: junit: 4.12 ' 

Cuando trabaja con varias bibliotecas de RxJava, es posible que encuentre un Archivos duplicados copiados en APK META-INF / DEPENDENCIAS Mensaje de error en tiempo de compilación. Si encuentra este error, la solución es suprimir estos archivos duplicados agregando lo siguiente a su nivel de módulo construir.gradle expediente:

android packagingOptions // Use "exclude" para señalar el archivo (o archivos) específico sobre el que Android Studio se está quejando // exclude 'META-INF / rxjava.properties'

Crear el diseño de la actividad principal

Sincronice sus archivos de Gradle, y luego cree un diseño que consiste en un Botón, un Editar texto, y un Vista de texto:

  

Codificar los enlaces del evento

Ahora veamos cómo usaría estos RxBinding para capturar los diversos eventos de IU a los que debe reaccionar nuestra aplicación. Para empezar, declara tus importaciones y define el Actividad principal clase. 

paquete com.jessicathornsby.myapplication; importar android.os.Bundle; importar android.support.v7.app.AppCompatActivity; importar android.widget.Button; importar android.widget.EditText; importar android.widget.TextView; importar android.widget.Toast; // Importe la clase view.RxView, para que pueda usar RxView.clicks // import com.jakewharton.rxbinding.view.RxView; // Importe widget.RxTextView para que pueda usar RxTextView.textChanges // import com.jakewharton.rxbinding.widget.RxTextView; la clase pública MainActivity extiende AppCompatActivity @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); Button button = (Button) findViewById (R.id.button); TextView textView = (TextView) findViewById (R.id.textView); EditText editText = (EditText) findViewById (R.id.editText); // El código para los enlaces va aquí // // ... //

Ahora puede comenzar a agregar enlaces para responder a eventos de IU. los RxView.clicks El método se utiliza para enlazar eventos de clic. Cree un enlace para mostrar un brindis cada vez que se haga clic en el botón:  

 RxView.clicks (botón) .subscribe (aVoid -> Toast.makeText (MainActivity.this, "RxView.clicks", Toast.LENGTH_SHORT) .show ();); 

A continuación, utilice el RxTextView.textChanges () Método para reaccionar ante un evento de cambio de texto actualizando el Vista de texto con los contenidos de nuestra Editar texto.

 RxTextView.textChanges (editText) .subscribe (charSequence -> textView.setText (charSequence);); 

Cuando ejecute su aplicación, terminará con una pantalla como la siguiente.

Instale su proyecto en un teléfono inteligente o tableta Android física o un AVD compatible, y luego pase un tiempo interactuando con los diversos elementos de la interfaz de usuario. Su aplicación debe reaccionar al hacer clic en eventos e ingreso de texto como de costumbre, y todo sin un oyente, TextWatcher o devolución de llamada a la vista!


RxBinding para vistas de biblioteca de soporte

Si bien la biblioteca RxBinding principal proporciona enlaces para todos los elementos de la interfaz de usuario que conforman la plataforma estándar de Android, también hay módulos hermanos RxBinding que proporcionan enlaces para las Vistas que se incluyen como parte de las diversas bibliotecas de soporte de Android..

Si ha agregado una o más bibliotecas de soporte a su proyecto, entonces, por lo general, también querrá agregar el módulo RxBinding correspondiente..

Estos módulos hermanos siguen una convención de nomenclatura sencilla que facilita la identificación de la biblioteca de soporte de Android correspondiente: cada módulo hermano simplemente toma el nombre de la biblioteca de soporte y reemplaza com.android con com.jakewharton.rxbinding2: rxbinding.

  • compile com.jakewharton.rxbinding2: rxbinding-recyclerview-v7: 2.0.0 '
  • compile 'com.jakewharton.rxbinding2: rxbinding-support-v4: 2.0.0'
  • compile 'com.jakewharton.rxbinding2: rxbinding-appcompat-v7: 2.0.0'
  • compile 'com.jakewharton.rxbinding2: rxbinding-design: 2.0.0'
  • compile 'com.jakewharton.rxbinding2: rxbinding-recyclerview-v7: 2.0.0'
  • compile 'com.jakewharton.rxbinding2: rxbinding-leanback-v17: 2.0.0'

Si está utilizando Kotlin en sus proyectos de Android, también hay una versión de Kotlin disponible para cada módulo RxBinding. Para acceder a la versión de Kotlin, simplemente agregue -Kotlin al nombre de la biblioteca con la que desea trabajar, por lo que:

compile 'com.jakewharton.rxbinding2: rxbinding-design: 2.0.0'

Se convierte en

compile 'com.jakewharton.rxbinding2: rxbinding-design-kotlin: 2.0.0'

Una vez que hayas convertido un Ver evento en un Observable, todos esos eventos se emiten como un flujo de datos. Como ya hemos visto, puede suscribirse a estas transmisiones y luego realizar cualquier tarea que necesite para desencadenar este evento de IU en particular, como mostrar una tostada o actualizando un Vista de texto. Sin embargo, también puede aplicar cualquiera de la enorme colección de operadores de RxJava a este flujo observable e incluso encadenar varios operadores para realizar transformaciones complejas en sus eventos de IU..

Hay demasiados operadores para discutir en un solo artículo (y la documentación oficial enumera a todos los operadores de todos modos) pero cuando se trata de trabajar con eventos de la interfaz de usuario de Android, hay algunos operadores que pueden ser particularmente útiles..

los rebotar () Operador

En primer lugar, si le preocupa que un usuario impaciente pueda tocar repetidamente un elemento de la interfaz de usuario, lo que podría confundir su aplicación, entonces puede usar la rebotar () operador para filtrar los eventos de IU que se emiten en rápida sucesión.

En el siguiente ejemplo, estoy especificando que este botón debe reaccionar a una Al hacer clic evento solo si ha habido al menos un espacio de 500 milisegundos desde el evento de clic anterior:

RxView.clicks (botón) .debounce (500, TimeUnit.MILLISECONDS) .subscribe (aVoid -> Toast.makeText (MainActivity.this, "RxView.clicks", Toast.LENGTH_SHORT) .show (););

los publicar() Operador

También puedes usar el publicar() operador para adjuntar varios oyentes a la misma vista, algo que tradicionalmente ha sido difícil de implementar en Android.

los publicar() operador convierte un estándar Observable en una conectable observable. Mientras que un observable normal comienza a emitir elementos tan pronto como el primer observador se suscribe a él, un observable conectable no emitirá nada hasta que usted lo indique explícitamente, aplicando el conectar() operador. Esto le brinda una oportunidad para suscribir múltiples observadores, sin que los elementos observables comiencen a emitir tan pronto como se realice la primera suscripción..

Una vez que haya creado todas sus suscripciones, simplemente aplique el conectar() El operador y el observable comenzarán a emitir datos a todos sus observadores asignados.  

Evite las fugas de memoria que rompen aplicaciones

Como hemos visto a lo largo de esta serie, RxJava puede ser una herramienta poderosa para crear aplicaciones de Android más reactivas e interactivas, con mucho menos código del que normalmente necesitaría para obtener los mismos resultados solo con Java. Sin embargo, hay un gran inconveniente en el uso de RxJava en sus aplicaciones de Android: el potencial de pérdidas de memoria causadas por suscripciones incompletas..

Estas fugas de memoria ocurren cuando el sistema Android intenta destruir una Actividad que contiene una carrera Observable. Como el observable se está ejecutando, su observador seguirá manteniendo una referencia a la actividad, y el sistema no podrá recolectar la basura como resultado de ello..

Desde que Android destruye y recrea Actividads cada vez que cambia la configuración del dispositivo, su aplicación podría estar creando un duplicado Actividad cada vez que el usuario cambia entre modo vertical y horizontal, así como cada vez que abre y cierra el teclado de su dispositivo.

Estas actividades se mantendrán en segundo plano, posiblemente nunca se recogerá la basura. Dado que las Actividades son objetos grandes, esto puede llevar rápidamente a grave problemas de administración de memoria, especialmente porque los teléfonos inteligentes y las tabletas con Android tienen una memoria limitada, para empezar. La combinación de una gran pérdida de memoria y una memoria limitada puede resultar rápidamente en una Sin memoria error.

Las fugas de memoria de RxJava pueden causar estragos en el rendimiento de su aplicación, pero hay una biblioteca de RxAndroid que le permite usar RxJava en su aplicación sin tener que preocuparse por las fugas de memoria..

La biblioteca RxLifecycle, desarrollada por Trello, proporciona las API de manejo del ciclo de vida que puede utilizar para limitar la vida útil de un Observable al ciclo de vida de un Actividad o Fragmento. Una vez que se establece esta conexión, RxLifecycle terminará la secuencia del observable en respuesta a los eventos del ciclo de vida que ocurren en la actividad o fragmento asignado de ese observable. Esto significa que puede crear un observable que finaliza automáticamente cada vez que se destruye una actividad o un fragmento.

Tenga en cuenta que estamos hablando de terminando una secuencia, y no darse de baja. Aunque a menudo se habla de RxLifecycle en el contexto de la gestión del proceso de suscripción / cancelación de la suscripción., técnicamente no anula la suscripción de un observador. En su lugar, la biblioteca RxLifecycle termina la secuencia observable emitiendo cualquiera de los dos onComplete () o onError () método. Cuando se da de baja, el observador deja de recibir notificaciones de su observable, incluso si ese observable sigue emitiendo elementos. Si específicamente requiere un comportamiento para darse de baja, entonces eso es algo que deberá implementar usted mismo.

Usando RxLifecycle

Para usar RxLifecycle en sus proyectos de Android, abra su nivel de módulo construir.gradle Archivo y agregue la última versión de la biblioteca RxLifeycle, más la biblioteca RxLifecycle de Android:

dependencias … compile 'com.trello.rxlifecycle2: rxlifecycle: 2.0.1' compile 'com.trello.rxlifecycle2: rxlifecycle-android: 2.0.1'

Luego, en el Actividad o Fragmento donde desee utilizar las API de manejo del ciclo de vida de la biblioteca, amplíe RxActividad, RxAppCompatActivity o RxFragment, y agregue la declaración de importación correspondiente, por ejemplo:

importar com.trello.rxlifecycle2.components.support.RxAppCompatActivity;… clase pública MainActivity extiende RxAppCompatActivity 

Cuando se trata de unir un Observable al ciclo de vida de un Actividad o Fragmento, puede especificar el evento del ciclo de vida donde el observable debe terminar, o puede dejar que la biblioteca RxLifecycle decida cuándo debe terminar la secuencia observable.

De manera predeterminada, RxLifecycle terminará un evento observable en el ciclo de vida complementario al evento en el que se produjo esa suscripción, por lo que si se suscribe a un observable durante su actividad onCreate () método, entonces RxLifecycle terminará la secuencia observable durante esa actividad onDestroy () método. Si te suscribes durante un Fragmentoes onAttach () método, entonces RxLifecycle terminará esta secuencia en el onDetach () método.

Puede dejar esta decisión hasta RxLifecycle, usando RxLifecycleAndroid.bindActivity:

Observable myObservable = Observable.range (0, 25);… @Override public void onResume () super.onResume (); myObservable .compose (RxLifecycleAndroid.bindActivity (lifecycle)) .subscribe (); 

Alternativamente, puede especificar el evento del ciclo de vida donde RxLifecycle debe terminar un Observable secuencia, usando RxLifecycle.bindUntilEvent.

Aquí, estoy especificando que la secuencia observable debe terminarse en onDestroy ():

@Override public void onResume () super.onResume (); myObservable .compose (RxLifecycle.bindUntilEvent (lifecycle, ActivityEvent.DESTROY)) .subscribe ();  

Trabajar con Android Marshmallow Permisos

La biblioteca final que veremos es RxPermissions, que fue diseñada para ayudarte a usar RxJava con el nuevo modelo de permisos introducido en Android 6.0. Esta biblioteca también le permite emitir una solicitud de permiso y manejar el resultado del permiso en la misma ubicación, en lugar de solicitar el permiso en un lugar y luego manejar sus resultados por separado, en Activity.onRequestPermissionsResult ().

Comience agregando la biblioteca RxPermissions a su construir.gradle expediente:

compile 'com.tbruyelle.rxpermissions2: rxpermissions: 0.9.3@aar'

Luego, crea una instancia de RxPermissions:

RxPermissions rxPermissions = new RxPermissions (this);

Entonces está listo para comenzar a realizar solicitudes de permisos a través de la biblioteca RxPermissions, utilizando la siguiente fórmula:

rxPermissions.request (Manifest.permission.READ_CONTACTS) .subscribe (concedido -> si (otorgado) // El permiso ha sido otorgado // else // El permiso ha sido denegado //);

Dónde emitir su solicitud de permisos es crucial, ya que siempre existe la posibilidad de que el alojamiento Actividad se puede destruir y luego volver a crear mientras el diálogo de permisos está en pantalla, generalmente debido a un cambio de configuración, como que el usuario se mueva entre los modos vertical y horizontal. Si esto ocurre, es posible que su suscripción no se vuelva a crear, lo que significa que no estará suscrito a RxPermissions observable y no recibirá la respuesta del usuario al cuadro de diálogo de solicitud de permiso. Para garantizar que su aplicación recibe la respuesta del usuario., siempre invocar su solicitud durante una fase de inicialización como Activity.onCreate ()Activity.onResume (), o View.onFinishInflate ().

No es raro que las funciones requieran varios permisos. Por ejemplo, enviar un mensaje SMS generalmente requiere que su aplicación tenga la ENVIAR SMS y LEER_CONTACTOS permisos La biblioteca RxPermissions proporciona un método conciso para emitir múltiples solicitudes de permisos y luego combinar las respuestas del usuario en una sola falso (uno o más permisos fueron denegados) o cierto (Todos los permisos fueron otorgados) respuesta a la que luego puede reaccionar.

RxPermissions.getInstance (this) .request (Manifest.permission.SEND_SMS, Manifest.permission.READ_CONTACTS) .subscribe (concedido -> if (concedido) // Todos los permisos fueron otorgados // else // Uno o más permisos fue negado//  );

Por lo general, deseará desencadenar una solicitud de permiso en respuesta a un evento de IU, como que el usuario toque un elemento o botón del menú, por lo que RxPermissions y RxBiding son dos bibliotecas que funcionan particularmente bien juntas.

El manejo del evento UI como un observable y la solicitud de permiso a través de RxPermissions le permite realizar una gran cantidad de trabajo con solo unas pocas líneas de código:

RxView.clicks (findViewById (R.id.enableBluetooth)) .compose (RxPermissions.getInstance (this) .ensure (Manifest.permission.BLUETOOTH_ADMIN)) .subscribe (concedido -> // Se ha hecho clic en el botón 'enableBluetooth' / /);

Conclusión

Después de leer este artículo, tiene algunas ideas de cómo eliminar una gran cantidad de código repetitivo de sus aplicaciones de Android: usar RxJava para manejar todos los eventos de IU de su aplicación y emitir sus solicitudes de permiso a través de RxPermissions. También vimos cómo puedes usar RxJava en cualquier Android Actividad o Fragmento, sin tener que preocuparse por las pérdidas de memoria que pueden ser causadas por suscripciones incompletas.

Hemos explorado algunas de las bibliotecas más populares y útiles de RxJava y RxAndroid de esta serie, pero si está ansioso por ver qué más tiene RxJava para ofrecer a los desarrolladores de Android, consulte algunas de las muchas otras bibliotecas de RxAndroid. Encontrará una lista completa de bibliotecas RxAndroid adicionales en GitHub.

Mientras tanto, echa un vistazo a algunas de nuestras otras publicaciones de desarrollo de Android aquí en Envato Tuts+!

  • Comience con Retrofit 2 HTTP Client

    Retrofit es un cliente HTTP seguro para el tipo para Android y Java. La actualización facilita la conexión a un servicio web REST al traducir la API a Java ...
    Chike Mgbemena
    SDK de Android
  • Introducción a Android Things

    En diciembre de 2016, Google lanzó una versión actualizada del sistema operativo Android con una opción para que los desarrolladores usen una versión simplificada para los conectados ...
    Paul Trebilcox-Ruiz
    Androide
  • Cómo hacer llamadas y usar SMS en aplicaciones de Android

    En este tutorial, aprenderá sobre la telefonía de Android y la API de SMS. Aprenderá cómo hacer una llamada desde su aplicación y cómo monitorear eventos de llamadas telefónicas, ...
    Chike Mgbemena
    SDK de Android
  • 6 Qué hacer y qué no hacer para una excelente experiencia de usuario de Android

    Las aplicaciones de Android más populares tienen algo en común: todas ofrecen una excelente experiencia de usuario. En esta publicación, compartiré algunos consejos que ayudarán a tu aplicación ...
    Jessica thornsby
    SDK de Android