RxJava 2.0 est une bibliothèque de programmation réactive populaire qui a aidé d'innombrables développeurs Android à créer des applications hautement réactives, utilisant moins de code et moins de complexité., notamment quand il s'agit de gérer plusieurs threads.
Si vous faites partie des nombreux développeurs qui ont migré vers Kotlin, cela ne signifie pas pour autant que vous deviez abandonner RxJava.!
Dans la première partie de cette série, je vous ai montré comment passer de la programmation avec RxJava 2.0 en Java à la programmation avec RxJava en Kotlin. Nous avons également examiné comment bannir les projets standard de vos projets en tirant parti des fonctions d'extension de RxKotlin, ainsi que le secret permettant d'éviter le problème de conversion SAM rencontré par de nombreux développeurs lorsqu'ils ont commencé à utiliser RxJava 2.0 avec Kotlin..
Dans cette deuxième partie, nous allons nous concentrer sur la façon dont RxJava peut vous aider à résoudre les problèmes que vous rencontrerez dans des projets Android réels, en créant une application Android réactive utilisant RxJava 2.0, RxAndroid et RxBinding..
Dans notre article sur la programmation réactive avec RxJava et RxKotlin, nous avons créé des Observables
et Observateurs
qui impriment des données sur Android Studio Logcat-mais ce n'est pas comme ça que vous utiliserez RxJava dans le monde réel.
Dans cet article, je vais vous montrer comment utiliser RxJava pour créer un écran utilisé dans d'innombrables applications Android: le classique S'inscrire écran.
Si votre application a tout type d’expérience d’inscription, il est généralement soumis à des règles strictes concernant le type d’information accepté. Par exemple, le mot de passe doit peut-être dépasser un certain nombre de caractères ou l'adresse de messagerie doit être dans un format de courrier électronique valide..
Pendant que tu pourrait vérifier l'entrée de l'utilisateur une fois qu'ils ont frappé le S'inscrire bouton, ce n'est pas la meilleure expérience utilisateur, car cela les laisse ouverts à la soumission d'informations qui ne seront clairement jamais acceptées par votre application.
Il est de loin préférable de surveiller l'utilisateur au cours de la frappe, puis de l'avertir dès qu'il devient évident qu'il entre des informations qui ne répondent pas aux exigences de votre application. En fournissant ce type de commentaires en direct et continus, vous donnez à l'utilisateur la possibilité de corriger ses erreurs. avant frapper ça S'inscrire bouton.
Pendant que tu pourrait surveiller l’activité des utilisateurs avec Kotlin, nous pouvons fournir cette fonctionnalité en utilisant beaucoup moins de code en faisant appel à RxJava, ainsi qu’à quelques autres bibliothèques associées.
Commençons par construire notre interface utilisateur. Je vais ajouter ce qui suit:
EditTexts
, où l'utilisateur peut entrer son adresse email (enterEmail
) et mot de passe (Entrer le mot de passe
).TextInputLayout
emballages, qui entourera notre enterEmail
et Entrer le mot de passe
EditTexts
. Ces wrappers afficheront un avertissement chaque fois que l'utilisateur entrera une adresse email ou un mot de passe qui ne répond pas aux exigences de notre application..Voici ma mise en page terminée:
Vous pouvez copier / coller ceci dans votre application si vous le souhaitez, ou vous pouvez simplement télécharger le code source du projet depuis notre dépôt GitHub..
Voyons maintenant comment utiliser RxJava, ainsi que quelques bibliothèques associées, pour surveiller les entrées des utilisateurs et fournir des commentaires en temps réel..
Je vais m'attaquer au S'inscrire écran en deux parties. Dans la première section, je vais vous montrer comment utiliser la bibliothèque RxBinding pour enregistrer et répondre aux événements de modification de texte. Dans la deuxième section, nous allons créer des fonctions de transformation qui valident l'entrée de l'utilisateur, puis afficherons un message d'erreur le cas échéant..
Créez un nouveau projet avec les paramètres de votre choix, mais lorsque vous y êtes invité, veillez à sélectionner le Inclure le support Kotlin case à cocher.
Dans cette section, nous allons implémenter les fonctionnalités suivantes:
enterEmail
champ.Pain grillé
. RxBinding est une bibliothèque qui facilite la conversion d'un grand nombre d'événements d'interface utilisateur en observables. Vous pouvez les traiter comme n'importe quel autre flux de données RxJava..
Nous allons surveiller les événements de changement de texte, en combinant les informations de RxBinding. widget.RxTextView
avec le afterTextChangeEvents
méthode, par exemple:
RxTextView.afterTextChangeEvents (enterEmail)
Le problème avec le traitement des événements de modification de texte en tant que flux de données est qu’au début, le enterEmail
et enterPassword EditTexts
sera vide, et nous ne voulons pas que notre application réagisse à cet état vide comme s'il s'agissait de la première émission de données du flux. RxBinding résout ce problème en fournissant un skipInitialValue ()
méthode que nous utiliserons pour demander à chaque observateur d'ignorer la valeur initiale de leur flux.
RxTextView.afterTextChangeEvents (enterEmail) .skipInitialValue ()
Je regarde la bibliothèque RxBinding plus en détail dans mon article sur RxJava 2 pour Android Apps.
.debounce ()
OpérateurPour offrir la meilleure expérience utilisateur possible, nous devons afficher tous les avertissements de mot de passe ou de courrier électronique pertinents une fois que l'utilisateur a fini de taper, mais avant de cliquer sur S'inscrire bouton.
Sans RxJava, l’identification de cette fenêtre temporelle nécessiterait généralement la mise en œuvre d’une Minuteur
, mais dans RxJava nous avons juste besoin d'appliquer le debounce ()
opérateur à notre flux de données.
Je vais utiliser le debounce ()
opérateur pour filtrer tous les événements de modification de texte qui se produisent dans une succession rapide, c’est-à-dire lorsque l’utilisateur tape encore. Ici, nous ignorons tous les événements de modification de texte qui se produisent dans la même fenêtre de 400 millisecondes:
RxTextView.afterTextChangeEvents (enterEmail) .skipInitialValue () .debounce (400, TimeUnit.MILLISECONDS)
AndroidSchedulers.mainThread ()
La bibliothèque de RxAndroid AndroidSchedulers.mainThread
nous donne un moyen facile de basculer vers le fil principal de l'interface utilisateur très important d'Android.
Dans la mesure où il est uniquement possible de mettre à jour l'interface utilisateur d'Android à partir du fil principal de l'interface utilisateur, nous devons nous assurer que nous sommes dans ce fil avant d'essayer d'afficher des avertissements d'e-mail ou de mot de passe, et avant d'afficher notre message. Pain grillé
.
RxTextView.afterTextChangeEvents (enterEmail) .skipInitialValue () .debounce (400, TimeUnit.MILLISECONDS) .observeOn (AndroidSchedulers.mainThread ())
Pour recevoir les données émises par enterEmail
, nous devons nous y abonner:
RxTextView.afterTextChangeEvents (enterEmail) .skipInitialValue () .debounce (400, TimeUnit.MILLISECONDS) .observeOn (AndroidSchedulers.mainThread ()) .subscribe
Finalement, nous voulons que notre application réponde aux événements de modification de texte en validant la saisie de l'utilisateur, mais pour que les choses restent simples, je vais simplement afficher un Pain grillé
.
Votre code devrait ressembler à ceci:
importer android.support.v7.app.AppCompatActivity importer android.os.Bundle importer android.widget.Toast importer importer com.jakewharton.rxbinding2.widget.RxTextView importer kotlinx.android.synthetic.main.activity_main. * importer io.reactivex.android .schedulers.AndroidSchedulers import java.util.concurrent.TimeUnit classe MainActivity: AppCompatActivity () override fun onCreate (savedInstanceState: Bundle?) super.onCréer (savedInstanceState) setContentView (R.layout.activity_Rony). skipInitialValue () .debounce (400, TimeUnit.MILLISECONDS) .observeOn (AndroidSchedulers.mainThread ()) .subscribe Toast.makeText (this, "400 millisecondes depuis le dernier changement de texte", Toast.LENGTH_SHORT) .show ()
Puisque nous utilisons plusieurs bibliothèques différentes, nous devons ouvrir le fichier de notre projet. build.gradle déposer et ajouter RxJava, RxBinding et RxAndroid en tant que dépendances du projet:
dépendances implementation fileTree (dir: 'libs', include: ['* .jar'])) implémentation "org.jetbrains.kotlin: kotlin-stdlib-jdk7: $ kotlin_version" implémentation "com.android.support:design:28.0. 0-alpha1 'implémentation' com.android.support:appcompat-v7:28.0.0-alpha1 'implémentation' com.android.support.constraint: constraint-layout: 1.1.0 '// Ajoute la dépendance RxJava // implémentation' io.reactivex.rxjava2: rxjava: 2.1.9 '// Ajoute la dépendance RxAndroid // // implémentation' io.reactivex.rxjava2: rxandroid: 2.0.2 '// Ajoute la dépendance RxBinding // implémentation' com.jakewharton.rxbinding2: Rxbinding: 2.1.1 '
Vous pouvez tester cette partie de votre projet en l'installant sur votre smartphone ou tablette Android physique ou sur votre périphérique virtuel Android (AVD). Sélectionnez le enterEmail
Éditer le texte
et commencez à taper; une Pain grillé
devrait apparaître lorsque vous arrêtez de taper.
Ensuite, nous devons définir quelques règles de base concernant le type d'entrée que notre application acceptera, puis comparer les entrées de l'utilisateur à ce critère et afficher un message d'erreur, le cas échéant..
Vérifier l'adresse e-mail ou le mot de passe de l'utilisateur est un processus en plusieurs étapes. Par conséquent, pour rendre notre code plus facile à lire, je vais combiner toutes ces étapes dans le leur. fonction de transformation.
Voici le début de la email validé
fonction de transformation:
// Définir un observableTransformer. L'entrée et la sortie doivent être une chaîne // valeur privée val validateEmailAddress = ObservableTransformerobservable -> // Utilisez flatMap pour appliquer une fonction à chaque élément émis par Observable // observable.flatMap // Coupez les espaces blancs au début et à la fin de l'entrée de l'utilisateur // Observable.just (it) .map it.trim () // Vérifie si l'entrée correspond au modèle de courrier électronique d'Android // .filter Patterns.EMAIL_ADDRESS.matcher (it) .matches ()
Dans le code ci-dessus, nous utilisons le filtre()
opérateur pour filtrer la sortie de l'Observable en fonction de son adéquation avec celle d'Android Patterns.EMAIL_ADDRESS
modèle.
Dans la partie suivante de la fonction de transformation, nous devons spécifier ce qui se passe si l’entrée ne correspond pas à la ADRESSE ÉLECTRONIQUE
modèle. Par défaut, chaque erreur irrécupérable déclenchera un appel à onError ()
, qui termine le flux de données. Au lieu de mettre fin au flux, nous voulons que notre application affiche un message d'erreur. Je vais donc utiliser onErrorResumeNext
, qui ordonne à l'Observable de réagir à une erreur en passant le contrôle à un nouvel Observable, plutôt que d'invoquer onError ()
. Cela nous permet d'afficher notre message d'erreur personnalisé.
// Si l'entrée de l'utilisateur ne correspond pas au modèle de courrier électronique, émettez une erreur // .singleOrError () .onErrorResumeNext if (c'est NoSuchElementException) Single.error (Exception ("Veuillez entrer une adresse email valide")) else Single.error (it) .toObservable ()
La dernière étape consiste à appliquer cette fonction de transformation au flux de données de courrier électronique, en utilisant le .composer()
opérateur. À ce stade, votre MainActivity.kt devrait ressembler à ceci:
import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.util.Patterns import io.reactivex.Observable import io.reactivex.ObservableTransformer import io.reactivex.Observable importation import kotlinx.android.synthetic.main.activity_main. * import java.util.concurrent.TimeUnit import com.jakewharton.rxbinding2.widget.RxTextView class MainActivity: AppCompatActivity () annule le plaisir surCreate (savedInstanceState: Bundle?) (savedInstanceState) setContentView (R.layout.activity_main) RxTextView.afterTextChangeEvents (enterEmail) .skipInitialValue () .map emailError.error = null it.view (). text.toString () .debounce (400, // Assurez-vous nous sommes dans le fil principal de l'interface utilisateur d'Android // TimeUnit.MILLISECONDS) .observeOn (AndroidSchedulers.mainThread ()) .compose (validateEmailAddress) .compose (retryWhenError passwordError.error = it.message) .subscribe () // If l'application rencontre une erreur, puis réessayez // fu inline privé n retryWhenError (crossinline onError: (ex: Throwable) -> Unit): ObservableTransformer= ObservableTransformer observable -> observable.retryWhen errors -> // Utilisez l'opérateur flatmap () pour aplatir toutes les émissions en un seul observable // errors.flatMap onError (it) Observable.just ("") / / Définir un ObservableTransformer, où nous effectuerons la validation de l’e-mail // valeur privée val validateEmailAddress = ObservableTransformer observable -> observable.flatMap Observable.just (it) .map it.trim () // Vérifie si la saisie de l'utilisateur correspond au modèle de courrier électronique d'Android // .filter Patterns.EMAIL_ADDRESS.matcher (it) .matches ( ) // Si l'entrée de l'utilisateur ne correspond pas au modèle de courrier électronique, lancez une erreur // .singleOrError () .onErrorResumeNext if (c'est NoSuchElementException) Single.error (Exception ("Entrez une adresse email valide" )) else Single.error (it) .toObservable ()
Installez ce projet sur votre appareil Android ou AVD et vous constaterez que la partie courrier électronique du S'inscrire l'écran vérifie maintenant votre saisie avec succès. Essayez d'entrer autre chose qu'une adresse e-mail et l'application vous avertira que cette entrée n'est pas valide..
À ce stade, nous avons un système entièrement fonctionnel. enterEmail
terrain et mise en œuvre Entrer le mot de passe
est principalement juste un cas de répéter les mêmes étapes.
En fait, la seule différence majeure est que notre validatePassword
La fonction de transformation doit vérifier différents critères. Je vais préciser que le mot de passe de l'utilisateur doit contenir au moins 7 caractères:
.filtre it.length> 7
Après avoir répété toutes les étapes précédentes, la tâche terminée MainActivity.kt devrait ressembler à ceci:
import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.util.Patterns import io.reactivex.Observable import io.reactivex.ObservableTransformer import io.reactivex.Observable importation import kotlinx.android.synthetic.main.activity_main. * import java.util.concurrent.TimeUnit import com.jakewharton.rxbinding2.widget.RxTextView class MainActivity: AppCompatActivity () annule le plaisir surCreate (savedInstanceState: Bundle?) (savedInstanceState) setContentView (R.layout.activity_main) // Répondre aux événements de modification de texte dans enterEmail // RxTextView.afterTextChangeEvents (enterEmail) // Ignorer l'état initial vide de enterEmail // .skipInitialValue () // Transformer les données émises / / .map emailError.error = null // Convertit l'entrée utilisateur en chaîne // it.view (). text.toString () // Ignore toutes les émissions qui se produisent dans un délai de 400 millisecondes // .debounce (400 , // Assurez-vous que nous sommes dans le fil principal de l'interface utilisateur d'Android // Tim eUnit.MILLISECONDS) .observeOn (AndroidSchedulers.mainThread ()) // Application de la fonction de transformation validateEmailAddress // .compose (validateEmailAddress) // Application de la fonction de transformation retryWhenError // .compose (retryWhenError emailError.error) .subscribe () // Rincez et répétez pour 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 l'application génère une erreur, réessayez / / private inline fun retryWhenError (crossinline onError: (ex: Throwable) -> Unit): ObservableTransformer= ObservableTransformer observable -> observable.retryWhen erreurs -> /// Utilisez l'opérateur flatmap () pour aplatir toutes les émissions en un seul observable // errors.flatMap onError (it) Observable.just ("") // Définit notre ObservableTransformer et spécifie que l'entrée et la sortie doivent être une chaîne // private val validatePassword = ObservableTransformer observable -> observable.flatMap Observable.just (it) .map it.trim () // Autorise uniquement les mots de passe d'au moins 7 caractères // .filter it.length> 7 // Si le Si le mot de passe est inférieur à 7 caractères, générez une erreur // .singleOrError () // Si une erreur se produit… // .onErrorResumeNext if (c'est NoSuchElementException) // Affiche le message suivant dans le passwordError TextInputLayout // Single. error (Exception ("Votre mot de passe doit comporter au moins 7 caractères")) Single.error (it) .toObservable () // Définit un ObservableTransformer, où nous effectuerons la validation de l'e-mail // privé. val validateEmailAddress = ObservableTransformer observable -> observable.flatMap Observable.just (it) .map it.trim () // Vérifie si la saisie de l'utilisateur correspond au modèle de courrier électronique d'Android // .filter Patterns.EMAIL_ADDRESS.matcher (it) .matches ( ) // Si l'entrée de l'utilisateur ne correspond pas au modèle d'e-mail… // .singleOrError () .onErrorResumeNext if (c'est NoSuchElementException) //// Affiche le message suivant dans l'emailError TextInputLayout // Single.error ( Exception ("Entrez une adresse électronique valide")) else Single.error (it) .toObservable ()
Installez ce projet sur votre appareil Android ou AVD et expérimentez la saisie au clavier. enterEmail
et Entrer le mot de passe
des champs. Si vous entrez une valeur qui ne répond pas aux exigences de l'application, le message d'avertissement correspondant s'affichera., sans pour autant vous devez appuyer sur le S'inscrire bouton.
Vous pouvez télécharger ce projet complet depuis GitHub.
Dans cet article, nous avons examiné comment RxJava peut aider à résoudre les problèmes concrets que vous rencontrerez lors du développement de vos propres applications Android, en utilisant RxJava 2.0, RxBinding et RxAndroid pour créer une S'inscrire écran.
Pour plus d'informations générales sur la bibliothèque RxJava, consultez notre article Premiers pas avec RxJava 2.0..