Programmation réactive Kotlin avec RxJava et RxKotlin

Depuis qu'il est devenu un langage officiellement pris en charge pour le développement Android, Kotlin a rapidement gagné en popularité parmi les développeurs Android, Google signalant une augmentation de 6 fois le nombre d'applications créées avec Kotlin..

Si vous avez déjà utilisé RxJava ou RxAndroid et souhaitez passer à Kotlin, ou si vous souhaitez démarrer une programmation réactive avec Kotlin, ce tutoriel est pour vous. Nous allons couvrir l'essentiel de la création de RxJava 2.0 Observateurs, Observables et flux de données dans Kotlin, avant de voir comment vous pouvez supprimer une tonne de code standard de vos projets, en combinant RxJava avec les fonctions d'extension Kotlin.

L'utilisation de RxJava avec Kotlin peut vous aider à créer des applications hautement réactives avec moins de code, mais aucun langage de programmation n'est parfait. Je partagerai donc une solution de contournement au problème de conversion SAM rencontré par de nombreux développeurs lorsqu'ils ont commencé à utiliser RxJava 2.0 avec Kotlin..

Pour conclure, nous allons créer une application qui montre comment utiliser RxJava pour résoudre certains des problèmes rencontrés dans les projets Android réels..

S'il s'agit de votre première expérience de RxJava, je vous fournirai également toutes les informations de base dont vous avez besoin pour comprendre les concepts de base de RxJava. Même si vous n'avez jamais expérimenté RxJava auparavant, à la fin de cet article, vous aurez une solide connaissance de l'utilisation de cette bibliothèque dans vos projets., et vous aurez créé plusieurs applications de travail à l'aide de RxJava, RxKotlin, RxAndroid et RxBinding.

Qu'est-ce que RxJava??

RxJava est une implémentation à source ouverte de la bibliothèque ReactiveX qui vous aide à créer des applications dans le style de programmation réactive. Bien que RxJava soit conçu pour traiter des flux de données synchrones et asynchrones, il n'est pas limité aux types de données «traditionnels». La définition de "données" par RxJava est assez large et inclut des éléments tels que les caches, les variables, les propriétés et même les événements d'entrée utilisateur tels que les clics et les balayages. Le fait que votre application ne traite pas de grands nombres ou n'effectue pas de transformations de données complexes ne signifie pas qu'elle ne puisse pas tirer parti de RxJava.!

Pour un peu d’information sur l’utilisation de RxJava pour les applications Android, vous pouvez consulter certains de mes autres articles ici sur Envato Tuts.+.

Alors, comment fonctionne RxJava?

RxJava étend le modèle de conception du logiciel Observer, basé sur le concept d’observateurs et d’observables. Pour créer un pipeline de données RxJava de base, vous devez:

  • Créer un observable.
  • Donne à l'observable des données à émettre.  
  • Créer un observateur.
  • Abonnez l'observateur à l'observable.

Dès que l'Observable aura au moins un observateur, il commencera à émettre des données. Chaque fois que l'Observable émet une donnée, il avertit l'observateur attribué en appelant le onNext () l’observateur effectuera alors généralement une action en réponse à cette émission de données. Une fois que l’Observable a fini d’émettre des données, il en informe l’observateur en appelant onComplete (). L’Observable se terminera alors et le flux de données prendra fin.

Si une exception se produit, alors onError () sera appelé, et l'Observable se terminera immédiatement sans émettre plus de données ni appeler onComplete ().

Mais RxJava n'est pas juste de passer des données d’un observable à un observateur! RxJava possède une vaste collection d'opérateurs que vous pouvez utiliser pour filtrer, fusionner et transformer ces données. Par exemple, imaginez que votre application possède un Payez maintenant bouton qui détecte sur clic événements, et vous craignez qu'un utilisateur impatient n'appuie plusieurs fois sur le bouton, ce qui entraînera le traitement de plusieurs paiements par votre application.  

RxJava vous permet de transformer ces sur clic événements dans un flux de données, que vous pouvez ensuite manipuler à l'aide des différents opérateurs de RxJava. Dans cet exemple particulier, vous pouvez utiliser le debounce () l'opérateur de filtrer les émissions de données qui se produisent en succession rapide, même si l'utilisateur trahit au loin Payez maintenant bouton, votre application n'enregistrera qu'un seul paiement.

Quels sont les avantages d'utiliser RxJava??

Nous avons vu comment RxJava peut vous aider à résoudre un problème spécifique, dans une application spécifique, mais que propose-t-il aux projets Android, en général?

RxJava peut vous aider à simplifier votre code en vous donnant un moyen d'écrire ce que vous voulez atteindre, plutôt que d'écrire une liste d'instructions que votre application doit suivre. Par exemple, si vous souhaitez ignorer toutes les émissions de données qui se produisent au cours de la même période de 500 millisecondes, écrivez:

.rebounce (500, TimeUnit.MILLISECONDS)

De plus, puisque RxJava traite presque tout En tant que données, il fournit un modèle que vous pouvez appliquer à un large éventail d'événements: créer un observable, créer un observateur, abonner l'observateur à l'observable, le rincer et le répéter. Cette approche avec formule donne un code beaucoup plus simple et lisible par l'homme.

L'autre avantage majeur pour les développeurs Android est que RxJava peut soulager le multithreading sur Android. Les utilisateurs mobiles d'aujourd'hui s'attendent à ce que leurs applications puissent effectuer plusieurs tâches à la fois, même s'il s'agit simplement de télécharger des données en arrière-plan tout en restant réactif aux données saisies par les utilisateurs..

Android dispose de plusieurs solutions intégrées pour créer et gérer plusieurs threads, mais aucune d'entre elles n'est particulièrement facile à mettre en œuvre. Elles peuvent rapidement générer un code complexe, détaillé, difficile à lire et sujet aux erreurs..

Dans RxJava, vous créez et gérez des threads supplémentaires à l'aide d'une combinaison d'opérateurs et de planificateurs. Vous pouvez facilement changer le fil où le travail est effectué, en utilisant le subscribeOn opérateur plus un planificateur. Par exemple, ici nous planifions le travail sur un nouveau thread:

.subscribeOn (Schedulers.newThread ())

Vous pouvez spécifier où les résultats de ce travail doivent être publiés, en utilisant le observer opérateur. Ici, nous publions les résultats sur le fil principal de l'interface utilisateur très important d'Android, à l'aide du AndroidSchedulers.mainThread planificateur, disponible dans la bibliothèque RxAndroid:

.observeOn (AndroidSchedulers.mainThread ())

Comparée aux solutions multithreading intégrées d'Android, l'approche de RxJava est beaucoup plus concis et plus facile à comprendre.

Encore une fois, vous pouvez en apprendre plus sur le fonctionnement de RxJava et sur les avantages de l’ajout de cette bibliothèque à votre projet dans mon article Premiers pas avec RxJava 2 pour Android.

Devrais-je utiliser RxJava ou RxKotlin?

Puisque Kotlin est 100% interopérable avec Java, vous pouvez utiliser la plupart des bibliothèques Java dans vos projets Kotlin sans aucune difficulté, et la bibliothèque RxJava ne fait pas exception..

est une bibliothèque RxKotlin dédiée, qui est un wrapper Kotlin autour de la bibliothèque RxJava normale. Ce wrapper fournit des extensions qui optimisent RxJava pour l’environnement Kotlin et peuvent réduire davantage la quantité de code standard que vous devez écrire..

Étant donné que vous pouvez utiliser RxJava dans Kotlin sans jamais avoir besoin de RxKotlin, nous utiliserons RxJava tout au long de cet article, sauf indication contraire..

Créer des observateurs simples et des observables à Kotlin

Observers et Observables sont les composants de base de RxJava. Commençons par créer:

  • Un simple observable qui émet un court flux de données en réponse à un événement de clic de bouton.
  • Un observable qui réagit à ces données en imprimant différents messages à Android Studio Logcat.

Créez un nouveau projet avec les paramètres de votre choix, mais assurez-vous de sélectionner le Inclure le support Kotlin case à cocher lorsque vous y êtes invité. Ensuite, ouvrez votre projet build.gradle fichier et ajoutez la bibliothèque RxJava en tant que dépendance du projet:

dépendances implementation fileTree (dir: 'libs', include: ['* .jar'])) implémentation "org.jetbrains.kotlin: kotlin-stdlib-jdk7: $ kotlin_version" androidx.appcompat: appcompat: 1.0.0- alpha1 'implémentation' androidx.constraintlayout: constraintlayout: 1.1.0 'implémentation' io.reactivex.rxjava2: rxjava: 2.1.9 '

Ensuite, ouvrez votre projet activity_main.xml déposer et ajouter le bouton qui va démarrer le flux de données:

  

Il existe plusieurs façons de créer un observable, mais l’un des plus faciles est d’utiliser le juste() opérateur pour convertir un objet ou une liste d'objets en observable.

Dans le code suivant, nous créons un observable (myObservable) et en lui donnant les articles 1, 2, 3, 4 et 5 à émettre. Nous créons également un observateur (myObserver), en le souscrivant à myObservable, puis en lui disant d'imprimer un message à Logcat chaque fois qu'il reçoit une nouvelle émission.

import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.util.Log import io.reactivex.Observable import io.reactivex.Observer import io.reactivex.disposables.Disposables.Disposable import kotlinx.android.synthetic.main . * class MainActivity: AppCompatActivity () private var TAG = "MainActivity" remplace fun onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Lance le flux en cliquant sur le bouton. // button.setOnClickListener startRStream () amusement privé startRStream () // Créer un observable // valeur myObservable = getObservable () // Créer un observateur // valeur myObserver = getObserver () // Souscrire myObserver à myObservable / / myObservable .subscribe (myObserver) amusement privé getObserver (): Observer retourne l'objet: Observer remplacez fun onSubscribe (d: Disposable)  // à chaque appel de onNext, affichez la valeur dans Logcat d'Android Studio // remplacez fun onNext (s: String) Log.d (TAG, "onNext: $ s")  // Appelé si une exception est levée // redéfinit fun onError (e: Throwable) Log.e (TAG, "onError:" + e.message) // // quand onComplete est appelé, affiche le texte suivant dans Logcat // redéfinissez fun onComplete () Log.d (TAG, "onComplete") // // donnez à myObservable des données à émettre // amusement privé getObservable (): Observable retourne Observable.just ("1", "2", "3", "4", "5")

Vous pouvez maintenant mettre cette application à l'épreuve:

  • Installez votre projet sur un smartphone ou une tablette physique Android, ou sur un périphérique virtuel Android (AVD).
  • Donner la Démarrer le flux RxJava bouton un clic.
  • Ouvrez Logcat Monitor d’Android Studio en sélectionnant le Moniteur Android onglet (où le curseur est positionné dans la capture d'écran suivante) puis en sélectionnant le Logcat languette.

À ce stade, l'observable commencera à émettre ses données et l'observateur imprimera ses messages à Logcat. Votre sortie Logcat devrait ressembler à ceci:

Vous pouvez télécharger ce projet depuis GitHub si vous voulez l'essayer vous-même..

Kotlin Extensions pour RxJava

Maintenant que nous avons vu comment configurer un pipeline RxJava simple dans Kotlin, voyons comment vous pouvez y parvenir dans Moins code, en utilisant les fonctions d'extension de RxKotlin.

Pour utiliser la bibliothèque RxKotlin, vous devez l'ajouter en tant que dépendance de projet:

dépendances implementation fileTree (dir: 'libs', include: ['* .jar'])) implémentation "org.jetbrains.kotlin: kotlin-stdlib-jdk7: $ kotlin_version" androidx.appcompat: appcompat: 1.0.0- alpha1 'implémentation' androidx.constraintlayout: constraintlayout: 1.1.0 'implémentation' io.reactivex.rxjava2: rxjava: 2.1.9 '// Ajouter le // implémentation suivante' io.reactivex.rxjava2: rxkotlin: 2.2.0 '

Dans l'exemple suivant, nous utilisons RxKotlin toObservable () fonction d'extension pour transformer un liste dans un observable. Nous utilisons également le subscribeBy () fonction d'extension, car elle nous permet de construire un observateur à l'aide d'arguments nommés, ce qui permet d'obtenir un code plus clair.

importer android.os.Bundle importer androidx.appcompat.app.AppCompatActivity importer io.reactivex.rxkotlin.subscribeBy importer io.reactivex.rxkotlin.toObservable import kotlinx.android.synthetic.main.activity_main fun onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Démarre le flux lorsque l'utilisateur clique sur le bouton // button.setOnClickListener startRStream () private fun startRStream ()  val list = listOf ("1", "2", "3", "4", "5") // Applique la fonction d'extension toObservable () // list.toObservable () // Construit votre observateur à l'aide de subscribeBy ( ) fonction d'extension // .subscribeBy (onNext = println (it), onError = it.printStackTrace (), onComplete = println ("onComplete!")

Voici le résultat que vous devriez voir:

Résoudre le problème d'ambiguïté SAM de RxJava

RxKotlin fournit également une solution de contournement importante au problème de conversion SAM susceptible de se produire lorsque plusieurs surcharges de paramètres SAM surviennent sur une méthode Java donnée. Cette ambiguïté SAM confond le compilateur Kotlin, car il ne peut pas déterminer l'interface à convertir, et la compilation de votre projet échouera..

Cette ambiguïté de SAM pose un problème particulier lors de l'utilisation de RxJava 2.0 avec Kotlin, car de nombreux opérateurs RxJava acceptent plusieurs types compatibles avec SAM..

Regardons le problème de conversion SAM en action. Dans le code suivant, nous utilisons le Zip *: français() opérateur de combiner la sortie de deux observables:  

import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import io.reactivex.Observable import kotlinx.android.synthetic.main.activity_main. * class MainActivity: AppCompatActivity () (Remplacez le contenu de l'événement par une erreur) .onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Démarre le flux lorsque l'utilisateur clique sur le bouton // button.setOnClickListener startRStream () fun privé startRStream () val numbers = Observable.range (1, 6 ) val strings = Observable.just ("Un", "Deux", "Trois", "Quatre", "Cinq", "Six") val zipped = Observable.zip (chaînes, nombres) s, n -> " $ s $ n " zipped.subscribe (:: println)

Cela entraînera le compilateur Kotlin à générer une erreur d'inférence de type. Cependant, RxKotlin fournit des méthodes d’aide et des fonctions d’extension aux opérateurs concernés, notamment: Observables.zip (), que nous utilisons dans le code suivant:

importer android.os.Bundle importer androidx.appcompat.app.AppCompatActivity importer io.reactivex.Observable importer io.reactivex.rxkotlin.Observables importer kotlinx.android.synthetic.main.activity_main. * class MainActivity (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Lance le flux en cliquant sur le bouton // button.setOnClickListener startRStream () private fun startRStream () val numbers = Observable.range (1, 6) val strings = Observable.just ("Un", "Deux", "Trois", "Quatre", "Cinq", "Six") val zipped = Observables.zip (chaînes, nombres ) s, n -> "$ s $ n" zipped.subscribe (:: println)

Voici la sortie de ce code:

Conclusion

Dans ce didacticiel, je vous ai montré comment commencer à utiliser la bibliothèque RxJava dans vos projets Kotlin, notamment en utilisant un certain nombre de bibliothèques supplémentaires, telles que RxKotlin et RxBinding. Nous avons étudié comment créer de simples observateurs et observables dans Kotlin, en passant par l'optimisation de RxJava pour la plate-forme Kotlin, à l'aide de fonctions d'extension..

Jusqu'à présent, nous avons utilisé RxJava pour créer de simples Observables qui émettent des données et des observateurs qui les impriment sur Logcat d'Android Studio - mais ce n'est pas ainsi que vous utiliserez RxJava dans le monde réel.!

Dans le prochain article, nous verrons comment RxJava peut vous aider à résoudre les problèmes concrets que vous rencontrerez lors du développement d'applications Android. Nous allons utiliser RxJava avec Kotlin pour créer un classique S'inscrire écran.