RxJava est l'une des bibliothèques les plus populaires pour intégrer la programmation réactive sur la plate-forme Android. Dans cette série en trois parties, je vous ai montré comment commencer à utiliser cette bibliothèque dans vos propres projets Android..
Dans Démarrer avec RxJava 2 pour Android, nous avons examiné ce qu'est RxJava et ce qu’il peut offrir aux développeurs Android avant de créer une application Hello World qui présente les trois composants de base de RxJava: une Observable
, un Observateur
, et un abonnement.
Dans le didacticiel Opérateurs de programmation réactive de RxJava 2, nous avons expliqué comment effectuer des transformations de données complexes à l’aide d’opérateurs et comment combiner Opérateur
le sable Planificateur
s pour enfin faire du multithreading sur Android une expérience sans douleur.
Nous avons également abordé RxAndroid, une bibliothèque spécialement conçue pour vous aider à utiliser RxJava dans vos projets Android, mais il reste encore beaucoup à explorer dans RxAndroid. Donc, dans ce post, je vais me concentrer uniquement sur la famille de bibliothèques RxAndroid.
Tout comme RxJava, RxAndroid a subi une refonte en profondeur dans sa version 2. L'équipe RxAndroid a décidé de modulariser la bibliothèque, en transférant une grande partie de ses fonctionnalités dans des modules complémentaires dédiés à RxAndroid..
Dans cet article, je vais vous montrer comment configurer et utiliser certains des modules les plus populaires et les plus puissants de RxAndroid, notamment une bibliothèque qui permet aux auditeurs, aux gestionnaires et aux Observateurs de texte
une chose du passé en vous donnant la possibilité de gérer tout Événement d'interface utilisateur Android en tant que Observable
.
Et comme les fuites de mémoire causées par des abonnements incomplets sont le principal inconvénient de l'utilisation de RxJava dans vos applications Android, je vais également vous montrer comment utiliser un module RxAndroid qui peut gérer le processus d'abonnement pour vous. À la fin de cet article, vous saurez utiliser RxJava dans tous Activité
ou Fragment
, sans courir le risque de rencontrer tout Fuites de mémoire liées à RxJava.
La réaction aux événements d'interface utilisateur tels que les taps, les glissements et la saisie de texte est un élément fondamental du développement de pratiquement toutes les applications Android, mais la gestion des événements d'interface utilisateur Android n'est pas particulièrement simple..
Vous réagirez généralement aux événements de l'interface utilisateur en utilisant une combinaison d'écouteurs, de gestionnaires, Observateurs de texte
, et éventuellement d'autres composants en fonction du type d'interface utilisateur que vous créez. Chacun de ces composants nécessite que vous écriviez une quantité importante de code passe-partout et, pour aggraver les choses, il n'y a aucune cohérence dans la façon dont vous implémentez ces différents composants. Par exemple, vous gérez Sur clic
événements en mettant en œuvre un OnClickListener
:
Bouton bouton = (Bouton) findViewById (R.id.button); button.setOnClickListener (nouvelle View.OnClickListener () @Override public void onClick (View v) // Effectuer quelques travaux //);
Mais ceci est complètement différent de la manière dont vous implémenteriez TextWatcher:
final EditText name = (EditText) v.findViewById (R.id.name); // Crée un TextWatcher et spécifie que ce TextWatcher doit être appelé à chaque fois que le contenu de EditText change // name.addTextChangedListener (new TextWatcher () @Override public void beforeTextChanged (CharSequence s, start, int count, int count, int after) @ Remplacer le vide public onTextChanged (CharSequence s, int start, int avant, int count) // Exécuter certains travaux // @Override public void afterTextChanged (Editable s) );
Ce manque de cohérence peut potentiellement ajouter beaucoup de complexité à votre code. Et si vous avez des composants d'interface utilisateur qui dépendent de la sortie d'autres composants d'interface utilisateur, préparez-vous à ce que les choses deviennent encore plus compliquées! Même un cas d'utilisation simple, comme demander à l'utilisateur de taper son nom dans un champ Éditer le texte
afin que vous puissiez personnaliser le texte qui apparaît dans la suite TextViews
-nécessite des rappels imbriqués, qui sont notoirement difficiles à mettre en œuvre et à maintenir. (Certaines personnes se réfèrent aux rappels imbriqués comme «enfer de rappel».)
De toute évidence, une approche standardisée de gestion des événements d'interface utilisateur peut grandement simplifier votre code. RxBinding est une bibliothèque qui se propose de le faire, en fournissant des liaisons qui vous permettent de convertir n'importe quel appareil Android. Vue
événement dans un Observable
.
Une fois que vous avez converti un événement view en un Observable
, il émettra ses événements d'interface utilisateur sous forme de flux de données auxquelles vous pouvez vous abonner exactement de la même manière que vous vous abonneriez à un autre Observable
.
Depuis que nous avons déjà vu comment capturer un événement de clic en utilisant le standard d'Android OnClickListener
, Voyons comment vous obtiendriez les mêmes résultats en utilisant RxBinding:
import com.jakewharton.rxbinding.view.RxView;… Bouton Bouton = (Bouton) findViewById (R.id.button); RxView.clicks (bouton) .subscribe (aVoid -> // Effectuer des travaux ici //);
Non seulement cette approche est-elle plus concise, mais il s'agit d'une implémentation standard que vous pouvez appliquer à tous les événements d'interface utilisateur qui se produisent dans votre application. Par exemple, la capture d’entrée de texte suit le même schéma que la capture d’événements de clic:
RxTextView.textChanges (editText) .subscribe (charSequence -> // Effectuer des travaux ici //);
Pour que vous puissiez voir exactement comment RxBinding peut simplifier le code lié à l'interface utilisateur de votre application, créons une application qui illustre quelques-unes de ces liaisons en action. Je vais aussi inclure un Vue
cela dépend de la sortie d'un autre Vue
, montrer comment RxBinding simplifie la création de relations entre les composants de l'interface utilisateur.
Cette application va consister en:
Bouton
qui affiche un Pain grillé
quand on tape.Éditer le texte
qui détecte les changements de texte.Affichage
qui met à jour pour afficher le contenu de la Éditer le texte
.Créez un projet Android Studio avec les paramètres de votre choix, puis ouvrez votre module build.gradle fichier et ajoutez la dernière version de la bibliothèque RxBinding en tant que dépendance du projet. Afin de réduire au minimum le code général, je vais également utiliser lambdas. J'ai donc mis à jour mon build.gradle Fichier pour prendre en charge cette fonctionnalité Java 8:
apply plugin: 'com.android.application' android compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig applicationId "com.jessicathornsby.myapplication" minSdkVersion 23 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner ". AndroidJUnitRunner "// Activer la chaîne d'outils Jack // jackOptions enabled true buildTypes release minifyEnabled false proguardFiles getDefaultProguardFile ('proguard-android.txt'), prog progres-project.pro ' Définir sourceCompatibility et targetCompatibility pour JavaVersion.VERSION_1_8 // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 dépendances compile fileTree (rép: 'libs', include: ['* .jar']) androidTestCompile ('com.android.support.test. : espresso-core: 2.2.2 ', groupe d'exclusion:' com.android.support ', module:' support-annotations ') // Ajoutez la bibliothèque principale RxBinding // compilez' com.jakewharton.rxbinding: rxbinding: 0.4.0 'compiler' com .android.support: appcompat-v7: 25.3.0 '// N'oubliez pas d'ajouter les dépendances RxJava et RxAndroid // compilez' io.reactivex.rxjava2: rxandroid: 2.0.1 'compilez' io.reactivex.rxjava2: rxjava: 2.0.5 'testCompile' junit: junit: 4.12 '
Lorsque vous travaillez avec plusieurs bibliothèques RxJava, il est possible que vous rencontriez un problème. Fichiers en double copiés dans APK META-INF / DEPENDENCIES message d'erreur lors de la compilation. Si vous rencontrez cette erreur, la solution de contournement consiste à supprimer ces fichiers en double en ajoutant ce qui suit à votre niveau de module build.gradle fichier:
android packagingOptions // Utilisez "exclude" pour désigner le (s) fichier (s) spécifique (s) qu'Android Studio se plaint // exclure 'META-INF / rxjava.properties'
Synchronisez vos fichiers Gradle, puis créez une mise en page composée d’un Bouton
, un Éditer le texte
, et un Affichage
:
Voyons maintenant comment vous utiliseriez ces RxBinding pour capturer les différents événements d'interface utilisateur auxquels notre application doit réagir. Pour commencer, déclarez vos importations et définissez le Activité principale
classe.
package com.jessicathornsby.myapplication; importer android.os.Bundle; importer android.support.v7.app.AppCompatActivity; importer android.widget.Button; importer android.widget.EditText; importer android.widget.TextView; importer android.widget.Toast; // Importe la classe view.RxView afin que vous puissiez utiliser RxView.clicks // import com.jakewharton.rxbinding.view.RxView; // Importez widget.RxTextView pour pouvoir utiliser RxTextView.textChanges // import com.jakewharton.rxbinding.widget.RxTextView; Classe publique MainActivity étend AppCompatActivity @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); Bouton bouton = (Bouton) findViewById (R.id.button); TextView textView = (TextView) findViewById (R.id.textView); EditText editText = (EditText) findViewById (R.id.editText); // Le code pour les liaisons va ici // //…… //
Vous pouvez maintenant commencer à ajouter des liaisons pour répondre aux événements de l'interface utilisateur. le RxView.clicks
Cette méthode est utilisée pour lier des événements de clic. Créez une liaison pour afficher un toast chaque fois que vous cliquez sur le bouton:
RxView.clicks (bouton) .subscribe (aVoid -> Toast.makeText (MainActivity.this, "RxView.clicks", Toast.LENGTH_SHORT) .show (););
Ensuite, utilisez le RxTextView.textChanges ()
méthode pour réagir à un événement de changement de texte en mettant à jour le Affichage
avec le contenu de notre Éditer le texte
.
RxTextView.textChanges (editText) .subscribe (charSequence -> textView.setText (charSequence););
Lorsque vous exécutez votre application, vous obtenez un écran comme celui-ci..
Installez votre projet sur un smartphone ou une tablette Android physique ou un AVD compatible, puis passez un certain temps à interagir avec les différents éléments de l'interface utilisateur. Votre application doit réagir aux événements de clic et à la saisie de texte comme d'habitude - et le tout sans écouteur, TextWatcher ou callback en vue!
Bien que la bibliothèque principale RxBinding fournisse des liaisons pour tous les éléments d'interface utilisateur constituant la plate-forme Android standard, il existe également des modules frères RxBinding qui fournissent des liaisons pour les vues incluses dans les différentes bibliothèques de support d'Android..
Si vous avez ajouté une ou plusieurs bibliothèques de support à votre projet, vous souhaiterez généralement ajouter le module RxBinding correspondant..
Ces modules frères suivent une convention de dénomination simple qui facilite l’identification de la bibliothèque de support Android correspondante: chaque module frère prend simplement le nom de la bibliothèque de support et remplace com.android
avec com.jakewharton.rxbinding2: rxbinding
.
compile com.jakewharton.rxbinding2: rxbinding-recyclerview-v7: 2.0.0 '
compiler 'com.jakewharton.rxbinding2: rxbinding-support-v4: 2.0.0'
compiler 'com.jakewharton.rxbinding2: rxbinding-appcompat-v7: 2.0.0'
compiler 'com.jakewharton.rxbinding2: rxbinding-design: 2.0.0'
compiler 'com.jakewharton.rxbinding2: rxbinding-recyclerview-v7: 2.0.0'
compiler 'com.jakewharton.rxbinding2: rxbinding-leanback-v17: 2.0.0'
Si vous utilisez Kotlin dans vos projets Android, une version Kotlin est également disponible pour chaque module RxBinding. Pour accéder à la version Kotlin, ajoutez simplement -Kotlin
au nom de la bibliothèque avec laquelle vous voulez travailler, alors:
compiler 'com.jakewharton.rxbinding2: rxbinding-design: 2.0.0'
Devient:
compiler 'com.jakewharton.rxbinding2: rxbinding-design-kotlin: 2.0.0'
Une fois que vous avez converti un Vue
événement dans un Observable
, tous ces événements sont émis sous forme de flux de données. Comme nous l’avons déjà vu, vous pouvez vous abonner à ces flux, puis exécuter toute tâche dont vous avez besoin pour déclencher cet événement d'interface utilisateur particulier, telle que l'affichage d'un Pain grillé
ou mettre à jour un Affichage
. Cependant, vous pouvez également appliquer n'importe quel ensemble d'opérateurs de RxJava à ce flux observable, et même chaîner plusieurs opérateurs pour effectuer des transformations complexes sur vos événements d'interface utilisateur..
Il y a beaucoup trop d'opérateurs à discuter dans un seul article (et la documentation officielle répertorie tous les opérateurs de toute façon), mais quand il s'agit de travailler avec des événements d'interface utilisateur Android, quelques opérateurs peuvent s'avérer particulièrement utiles..
debounce ()
OpérateurTout d'abord, si vous craignez qu'un utilisateur impatient ne touche à un élément de l'interface utilisateur de manière répétée, ce qui pourrait prêter à confusion pour votre application, vous pouvez utiliser la debounce ()
opérateur pour filtrer tous les événements d'interface utilisateur qui sont émis en succession rapide.
Dans l’exemple suivant, je précise que ce bouton doit réagir à une Sur clic
événement uniquement s'il y a eu un intervalle d'au moins 500 millisecondes depuis l'événement clic précédent:
RxView.clicks (bouton) .debounce (500, TimeUnit.MILLISECONDS) .subscribe (aVoid -> Toast.makeText (MainActivity.this, "RxView.clicks", Toast.LENGTH_SHORT) .show (););
publier()
OpérateurVous pouvez également utiliser le publier()
opérateur pour attacher plusieurs auditeurs à la même vue, ce qui était traditionnellement difficile à implémenter dans Android.
le publier()
l'opérateur convertit une norme Observable
dans une connectable observable. Alors qu'un observable régulier commence à émettre des éléments dès que le premier observateur s'y est abonné, un observable connectable n'émettra rien jusqu'à ce que vous le lui donniez explicitement, en appliquant le bouton relier()
opérateur. Cela vous donne une fenêtre d’opportunité pour abonner plusieurs observateurs sans que l’observable ne commence à émettre des éléments dès le premier abonnement..
Une fois que vous avez créé tous vos abonnements, appliquez simplement le relier()
l'opérateur et l'observable commenceront à émettre des données à tous les observateurs qui lui sont assignés.
Comme nous l'avons vu tout au long de cette série, RxJava peut être un outil puissant pour créer des applications Android interactives plus réactives, avec beaucoup moins de code que vous n'auriez normalement besoin pour obtenir les mêmes résultats en utilisant uniquement Java. Cependant, l'utilisation de RxJava dans vos applications Android présente un inconvénient majeur: le risque de fuite de mémoire dû à des abonnements incomplets..
Ces fuites de mémoire se produisent lorsque le système Android tente de détruire un Activité
qui contient une course Observable
. Puisque l'observable est en cours d'exécution, son observateur conservera toujours une référence à l'activité et le système ne pourra pas récupérer cette activité..
Depuis Android détruit et recrée Activité
s chaque fois que la configuration de l'appareil change, votre application peut créer un doublon Activité
chaque fois que l'utilisateur bascule entre les modes portrait et paysage, ainsi que chaque fois qu'il ouvre et ferme le clavier de son appareil.
Ces activités resteront à l’arrière-plan et ne seront jamais récupérées. Les activités étant de gros objets, cela peut rapidement conduire à sérieux problèmes de gestion de la mémoire, d’autant plus que les smartphones et tablettes Android ont d’abord une mémoire limitée. La combinaison d’une fuite de mémoire importante et d’une mémoire limitée peut rapidement entraîner Mémoire insuffisante Erreur.
Les fuites de mémoire de RxJava peuvent avoir des effets dévastateurs sur les performances de votre application, mais il existe une bibliothèque RxAndroid qui vous permet d'utiliser RxJava dans votre application sans avoir à vous soucier des fuites de mémoire..
La bibliothèque RxLifecycle, développée par Trello, fournit des API de gestion du cycle de vie que vous pouvez utiliser pour limiter la durée de vie d’une machine. Observable
au cycle de vie d'un Activité
ou Fragment
. Une fois cette connexion établie, RxLifecycle met fin à la séquence de l'observable en réponse à des événements de cycle de vie qui se produisent dans l'activité ou le fragment attribué à cet observable. Cela signifie que vous pouvez créer un observable qui se termine automatiquement chaque fois qu'une activité ou un fragment est détruit..
Notez que nous parlons de se terminant une séquence, et non désinscription. Bien que RxLifecycle soit souvent évoqué dans le contexte de la gestion du processus d’abonnement / désabonnement, techniquement il ne désabonne pas un observateur. Au lieu de cela, la bibliothèque RxLifecycle termine la séquence observable en émettant soit le onComplete ()
ou onError ()
méthode. Lorsque vous vous désabonnez, l'observateur cesse de recevoir des notifications de son observable, même si cet observable continue d'émettre des éléments. Si vous souhaitez spécifiquement un comportement de désinscription, vous devrez le mettre en œuvre vous-même..
Pour utiliser RxLifecycle dans vos projets Android, ouvrez votre module build.gradle fichier et ajoutez la dernière version de la bibliothèque RxLifeycle, plus la bibliothèque RxLifecycle Android:
dépendances … compile 'com.trello.rxlifecycle2: rxlifecycle: 2.0.1' compile 'com.trello.rxlifecycle2: rxlifecycle-android: 2.0.1'
Ensuite, dans le Activité
ou Fragment
où vous voulez utiliser les API de gestion du cycle de vie de la bibliothèque, étendez-vous soit RxActivity
, RxAppCompatActivity
ou RxFragment
, et ajoutez l'instruction d'importation correspondante, par exemple:
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;… classe publique MainActivity étend RxAppCompatActivity
Quand il s’agit de lier un Observable
au cycle de vie d'un Activité
ou Fragment
, vous pouvez soit spécifier l'événement de cycle de vie auquel l'observable doit se terminer, soit vous pouvez laisser la bibliothèque RxLifecycle décider du moment où elle doit terminer la séquence observable.
Par défaut, RxLifecycle terminera un événement observable dans l'événement de cycle de vie complémentaire à celui où cet abonnement s'est produit. Par conséquent, si vous vous abonnez à un événement observable pendant votre activité. onCreate ()
méthode, alors RxLifecycle terminera la séquence observable au cours de cette activité onDestroy ()
méthode. Si vous vous abonnez pendant un Fragment
de onAttach ()
méthode, alors RxLifecycle mettra fin à cette séquence dans le onDetach ()
méthode.
Vous pouvez laisser cette décision jusqu'à RxLifecycle en utilisant RxLifecycleAndroid.bindActivity
:
ObservablemyObservable = Observable.range (0, 25);… @Override public void onResume () super.onResume (); myObservable .compose (RxLifecycleAndroid.bindActivity (cycle de vie)) .subscribe ();
Vous pouvez également spécifier l’événement du cycle de vie où RxLifecycle doit terminer un Observable
séquence en utilisant RxLifecycle.bindUntilEvent
.
Ici, je précise que la séquence observable doit être terminée dans onDestroy ()
:
@Override public void onResume () super.onResume (); myObservable .compose (RxLifecycle.bindUntilEvent (cycle de vie, ActivityEvent.DESTROY)) .subscribe ();
La dernière bibliothèque que nous allons examiner est RxPermissions, qui a été conçue pour vous aider à utiliser RxJava avec le nouveau modèle de permissions introduit dans Android 6.0. Cette bibliothèque vous permet également d’émettre une demande d’autorisation et de gérer le résultat de l’autorisation au même endroit, au lieu de demander l’autorisation au même endroit, puis de gérer ses résultats séparément, Activity.onRequestPermissionsResult ()
.
Commencez par ajouter la bibliothèque RxPermissions à votre build.gradle fichier:
compile 'com.tbruyelle.rxpermissions2: rxpermissions: 0.9.3@aar'
Ensuite, créez une instance de RxPermissions:
RxPermissions rxPermissions = nouveau RxPermissions (this);
Vous êtes alors prêt à commencer à faire des demandes d'autorisation via la bibliothèque RxPermissions, en utilisant la formule suivante:
rxPermissions.request (Manifest.permission.READ_CONTACTS) .subscribe (accordé -> if (accordé) // L'autorisation a été accordée // else // L'autorisation a été refusée //);
Où vous émettez votre demande d'autorisations est cruciale, car il y a toujours une chance que l'hébergement Activité
peuvent être détruits puis recréés lorsque le dialogue des autorisations est à l'écran, généralement en raison d'un changement de configuration tel que l'utilisateur se déplace entre les modes portrait et paysage. Si cela se produit, votre abonnement peut ne pas être recréé, ce qui signifie que vous ne serez pas abonné à l'observable RxPermissions et ne recevrez pas la réponse de l'utilisateur à la boîte de dialogue de demande d'autorisation. Pour garantir que votre application reçoit la réponse de l'utilisateur, toujours invoquer votre demande lors d'une phase d'initialisation telle que Activity.onCreate ()
, Activité.Resume ()
, ou View.onFinishInflate ()
.
Il n'est pas rare que des fonctionnalités nécessitent plusieurs autorisations. Par exemple, pour envoyer un SMS, votre application doit généralement disposer du ENVOYER UN SMS
et READ_CONTACTS
autorisations. La bibliothèque RxPermissions fournit une méthode concise pour émettre plusieurs demandes d’autorisation, puis pour combiner les réponses de l’utilisateur en une seule. faux
(une ou plusieurs autorisations ont été refusées) ou vrai
(toutes les autorisations ont été accordées) réponse à laquelle vous pouvez ensuite réagir en conséquence.
RxPermissions.getInstance (this) .request (Manifest.permission.SEND_SMS, Manifest.permission.READ_CONTACTS) .subscribe (accordé -> if (accordé) // Toutes les autorisations ont été accordées // else // Une ou plusieurs autorisations a été refusé// );
En règle générale, vous souhaiterez déclencher une demande d'autorisation en réponse à un événement d'interface utilisateur, par exemple si l'utilisateur appuie sur un élément de menu ou un bouton. RxPermissions et RxBiding sont donc deux bibliothèques qui fonctionnent particulièrement bien ensemble..
Le fait de gérer l'événement d'interface utilisateur comme observable et d'effectuer la demande d'autorisation via RxPermissions vous permet d'effectuer beaucoup de travail avec seulement quelques lignes de code:
RxView.clicks (findViewById (R.id.enableBluetooth)) .compose (RxPermissions.getInstance (this) .ensure (Manifest.permission.BLUETOOTH_ADMIN)) .subscribe (accordé -> // Le bouton 'enableBluetooth' a été cliqué / /);
Après avoir lu cet article, vous avez quelques idées sur la façon de couper beaucoup de code standard dans vos applications Android: utiliser RxJava pour gérer tous les événements d'interface utilisateur de votre application et émettre vos demandes d'autorisation via RxPermissions. Nous avons également examiné comment utiliser RxJava sous Android. Activité
ou Fragment
, sans avoir à vous soucier des fuites de mémoire pouvant être causées par des abonnements incomplets.
Nous avons exploré certaines des bibliothèques les plus populaires et les plus utiles de RxJava et de RxAndroid de cette série, mais si vous souhaitez savoir ce que RxJava a à offrir aux développeurs Android, découvrez certaines des nombreuses autres bibliothèques RxAndroid. Vous trouverez une liste complète des bibliothèques supplémentaires RxAndroid sur GitHub.
En attendant, consultez quelques-uns de nos autres messages de développement Android ici sur Envato Tuts+!