Débuter avec ReactiveX sur Android

introduction

Développer une application Android complexe comportant un grand nombre de connexions réseau, d'interactions utilisateur et d'animations implique souvent l'écriture de code rempli de rappels imbriqués. Ce code, parfois appelé enfer de rappel, est non seulement long et difficile à comprendre, mais également sujet aux erreurs. ReactiveX offre une approche alternative à la fois claire et concise pour gérer les tâches et les événements asynchrones..

RxJava est une implémentation JVM de ReactiveX, développée par NetFlix, et est très populaire parmi les développeurs Java. Dans ce didacticiel, vous apprendrez à utiliser les liaisons RxJava pour Android, ou RxAndroid en abrégé, dans vos projets Android..

1. Configuration de RxAndroid

Pour utiliser RxAndroid dans un projet Android Studio, ajoutez-le en tant que compiler dépendance dans le module d'application build.gradle.

java compile 'io.reactivex: rxandroid: 0.25.0'

2. Bases des observateurs et observables

Lorsque vous travaillerez avec ReactiveX, vous utiliserez beaucoup d’observables et d’observateurs. Vous pouvez considérer un observable comme un objet émettant des données et un observateur comme un objet consommant ces données. Dans RxJava et RxAndroid, les observateurs sont des exemples de Observateur interface, et observables sont des instances de la Observable classe.

le Observable la classe a beaucoup de méthodes statiques, appelées les opérateurs, créer Observable objets. Le code suivant vous montre comment utiliser le juste opérateur pour créer un très simple Observable qui émet un seul Chaîne.

java observable myObservable = Observable.just ("Hello"); // émet "Bonjour"

L'observable que nous venons de créer émettra ses données uniquement s'il y a au moins un observateur. Pour créer un observateur, vous créez une classe qui implémente le Observateur interface. le Observateur interface possède des méthodes nommées de manière intuitive pour gérer les différents types de notifications qu’elle peut recevoir de l’observable. Voici un observateur qui peut imprimer le Chaîne émis par l'observable que nous avons créé précédemment:

"java observateur myObserver = new Observer() @Override public void onCompleted () // Appelé lorsque l'observable n'a plus de données à émettre

@Override public void onError (Throwable e) // Appelé lorsque l'observable rencontre une erreur @Override public void onNext (String s) // Appelé chaque fois que l'observable émet des données Log.d ("MY OBSERVER", s) ; ; "

Pour affecter un observateur à un observable, vous devez utiliser le souscrire méthode, qui retourne un Abonnement objet. Le code suivant fait myObserver observer myObservable:

java Subscription mySubscription = myObservable.subscribe (myObserver);

Dès qu'un observateur est ajouté à l'observable, il émet ses données. Par conséquent, si vous exécutez le code maintenant, vous verrez Bonjour imprimé dans Android Studio logcat la fenêtre.

Vous avez peut-être remarqué que nous n'avons pas utilisé le onCompleted et le onError méthodes en myObserver. Comme ces méthodes restent souvent inutilisées, vous avez également la possibilité d’utiliser le Action1 interface, qui contient une seule méthode nommée appel.

java Action1 myAction = new Action1() @Override public void call (String s) Log.d ("My Action", s); ;

Lorsque vous passez une instance de Action1 au souscrire méthode, la appel la méthode est invoquée chaque fois que l'observable émet des données.

java Subscription mySubscription = myObservable.subscribe (myAction1);

Pour détacher un observateur de son observable pendant que celui-ci émet toujours des données, vous pouvez appeler le Se désabonner méthode sur le Abonnement objet.

java mySubscription.unsubscribe ();

3. Utilisation des opérateurs

Maintenant que vous savez comment créer des observateurs et des observables, laissez-moi vous montrer comment utiliser les opérateurs de ReactiveX pouvant créer, transformer et effectuer d'autres opérations sur des observables. Commençons par créer un peu plus avancé Observable, celui qui émet des éléments d'un tableau de Entier objets. Pour ce faire, vous devez utiliser le de opérateur, qui peut générer une Observable des tableaux et des listes.

"java observable myArrayObservable = Observable.from (nouvel Integer [] 1, 2, 3, 4, 5, 6); // émet chaque élément du tableau, un à la fois

myArrayObservable.subscribe (nouvelle Action1() @Override appel public vide (Integer i) Log.d ("Mon action", String.valueOf (i)); // Imprime le nombre reçu); ""

Lorsque vous exécutez ce code, vous verrez chaque numéro du tableau imprimé les uns après les autres..

Si vous connaissez JavaScript, Ruby ou Kotlin, vous connaissez peut-être des fonctions d'ordre supérieur telles que carte et filtre, qui peut être utilisé lorsque vous travaillez avec des tableaux. ReactiveX a des opérateurs qui peuvent effectuer des opérations similaires sur des observables. Cependant, Java 7 ne disposant pas de lambdas ni de fonctions d'ordre supérieur, nous devrons le faire avec des classes simulant des lambdas. Pour simuler un lambda prenant un argument, vous devez créer une classe qui implémente le Func1 interface.

Voici comment vous pouvez utiliser le carte opérateur pour mettre en carré chaque élément de myArrayObservable:

java myArrayObservable = myArrayObservable.map (nouveau Func1() // Input et Output sont tous les deux Integer @Override public Appel entier (Entier entier) return integer * integer; // Place le nombre);

Notez que l'appel à la carte l'opérateur renvoie un nouveau Observable, ça ne change pas l'original Observable. Si vous êtes abonné à myArrayObservable maintenant, vous recevrez des carrés des nombres.

Les opérateurs peuvent être chaînés. Par exemple, le bloc de code suivant utilise le sauter opérateur pour ignorer les deux premiers chiffres, puis le filtre opérateur pour ignorer les nombres impairs:

"java myArrayObservable .skip (2) // Ignore les deux premiers éléments .filter (new Func1() @Override public Appel booléen (Entier entier) // Ignore tout élément renvoyant un entier faux renvoyé% 2 == 0; );

// émet 4 et 6 "

4. Gestion des travaux asynchrones

Les observateurs et les observables que nous avons créés dans les sections précédentes travaillaient sur un seul thread, le thread de l'interface utilisateur d'Android. Dans cette section, je vais vous montrer comment utiliser ReactiveX pour gérer plusieurs threads et comment ReactiveX résout le problème de l'enfer de rappel..

Supposons que vous avez une méthode nommée fetchData qui peut être utilisé pour récupérer les données d’une API. Supposons qu’il accepte une URL en tant que paramètre et renvoie le contenu de la réponse sous forme de Chaîne. L'extrait de code suivant montre comment il pourrait être utilisé.

java String content = fetchData ("http://www.google.com"); // récupère le contenu de google.com sous forme de chaîne

Cette méthode doit être exécutée sur son propre thread, car Android n'autorise pas les opérations réseau sur le thread d'interface utilisateur. Cela signifie que vous créez soit un AsyncTask ou créer un Fil qui utilise un Gestionnaire.

Avec ReactiveX, cependant, vous avez une troisième option légèrement plus concise. En utilisant le subscribeOn et observer opérateurs, vous pouvez spécifier explicitement quel thread doit exécuter le job d’arrière-plan et quel thread doit gérer les mises à jour de l’interface utilisateur.

Le code suivant crée une coutume Observable en utilisant le créer opérateur. Lorsque vous créez un Observable de cette manière, vous devez mettre en œuvre le Observable.OnSubscribe interface et contrôle ce qu’il émet en appelant le onNext, onError, et onCompleted méthodes vous-même.

java observable fetchFromGoogle = Observable.create (nouveau Observable.OnSubscribe() @Override public void call (abonné) abonné) try String data = fetchData ("http://www.google.com"); subscriber.onNext (data); // Emet le contenu de l'URL subscriber.onCompleted (); // Rien de plus à émettre catch (exception e) subscriber.onError (e); // S'il y a des erreurs de réseau);

Quand le Observable est prêt, vous pouvez utiliser subscribeOn et observer pour spécifier les threads qu'il doit utiliser et s'y abonner.

java fetchFromGoogle .subscribeOn (Schedulers.newThread ()) // Créer un nouveau thread .observeOn (AndroidSchedulers.mainThread ()) // Utiliser le fil de l'interface utilisateur .subscribe (new Action1() @Override appel public void (String s) view.setText (view.getText () + "\ n" + s); // Changer une vue);

Vous pensez peut-être encore que l'approche réactive n'est pas radicalement meilleure que d'utiliser le AsyncTask ou Gestionnaire Des classes. Vous avez raison, vous n'avez pas vraiment besoin de ReactiveX si vous ne devez gérer qu'un seul travail en arrière-plan.

Considérons maintenant un scénario qui aboutirait à une base de code complexe si vous utilisiez l'approche conventionnelle. Supposons que vous deviez récupérer les données de deux sites Web (ou plus) en parallèle et mettre à jour un fichier. Vue seulement lorsque toutes les demandes sont terminées. Si vous suivez l'approche classique, vous devrez écrire beaucoup de code inutile pour vous assurer que les demandes sont traitées sans erreur..

Envisagez un autre scénario dans lequel vous devez démarrer un travail en arrière-plan uniquement après la fin d'un autre travail en arrière-plan. En utilisant l'approche conventionnelle, cela entraînerait des rappels imbriqués.

Avec les opérateurs de ReactiveX, les deux scénarios peuvent être gérés avec très peu de code. Par exemple, si vous devez utiliser fetchData pour récupérer le contenu de deux sites Web, par exemple Google et Yahoo, vous devez créer deux Observable objets, et utiliser le subscribeOn méthode pour les faire fonctionner sur des threads différents.

java fetchFromGoogle = fetchFromGoogle.subscribeOn (Schedulers.newThread ()); fetchFromYahoo = fetchFromYahoo.subscribeOn (Schedulers.newThread ());

Pour gérer le premier scénario dans lequel les deux demandes doivent s'exécuter en parallèle, vous pouvez utiliser le Zip *: français opérateur et abonnez-vous au Observable il revient.

java // Récupération simultanée des deux observables zipped = Observable.zip (fetchFromGoogle, fetchFromYahoo, nouveau Func2() @Override public String call (String google, String yahoo) // Faites quelque chose avec les résultats des deux threads return google + "\ n" + yahoo; );

De même, pour gérer le second scénario, vous pouvez utiliser le concat opérateur pour exécuter les threads l'un après l'autre.

java observable concatenated = Observable.concat (fetchFromGoogle, fetchFromYahoo); // émet les résultats les uns après les autres

5. Manipulation d'événements

RxAndroid a une classe nommée VoirObservable qui facilite la gestion des événements associés à Vue objets. L’extrait de code suivant vous montre comment créer un VoirObservable qui peut être utilisé pour gérer les événements de clic d'un Bouton.

"java Button monBouton = (Bouton) findViewById (R.id.my_button); // Créer un bouton à partir d'une mise en page

Observable clicksObservable = ViewObservable.clicks (myButton); // Créer un ViewObservable pour le bouton "

Vous pouvez maintenant vous abonner à clicksObservable et utilisez l’un des opérateurs que vous avez appris dans les sections précédentes. Par exemple, si vous souhaitez que votre application ignore les quatre premiers clics du bouton et commence à répondre à partir du cinquième clic, vous pouvez utiliser l'implémentation suivante:

java clicksObservable .skip (4) // Ignore les 4 premiers clics .subscribe (nouvelle Action1() @Override appel public vide (OnClickEvent onClickEvent) Log.d ("Action Clic", "Cliqué!"); // Imprimé à partir du cinquième clic);

Conclusion

Dans ce didacticiel, vous avez appris à utiliser les observateurs, les observables et les opérateurs de ReactiveX pour gérer plusieurs opérations et événements asynchrones. Travailler avec ReactiveX implique une programmation fonctionnelle et réactive, paradigme de la programmation auquel la plupart des développeurs Android ne sont pas habitués. Ne soyez pas trop dur envers vous-même si vous ne réussissez pas du premier coup. Vous devez également savoir que le code ReactiveX sera beaucoup plus lisible si vous utilisez un langage de programmation moderne, tel que Kotlin, qui prend en charge les fonctions d'ordre supérieur..

Pour en savoir plus sur les extensions réactives, je vous encourage à parcourir les ressources disponibles sur ReactiveX..