Si vous lisez ce cours, c'est que normalement, votre niveau est déjà assez avancé dans le développement d'applications mobile sur Android... :)
À force de développer des mini-applications grâce aux différents cours de notre parcours Android, vous vous êtes peut-être posé la question suivante : existe-t-il une architecture logicielle optimale pour développer une application Android ?
Tout à fait ! Car il est vrai que, parfois, mes contrôleurs (activités et/ou fragments) me semblent un peu trop gros... :'(
Exactement ! Ce phénomène, connu sur iOS sous l'appellation "Massive View Controller", se produit lorsqu'un de vos contrôleurs (activités et/ou fragments) contient beaucoup trop de code et qu'il en devient presque illisible voire instable, et quasiment intestable.
C'est vrai que j'ai tendance à écrire beaucoup de choses dans mes activités... Mais il faut dire que la moindre fonctionnalité sur Android demande beaucoup de lignes de code !
Nous sommes d'accord ! :D De plus, comme vous l'avez déjà probablement remarqué sur Android, vos contrôleurs ont un cycle de vie assez particulier. En effet, ces derniers peuvent être détruits à n'importe quel moment, emportant avec eux l'ensemble des données qu'ils contenaient. Cela peut être produit lors de rotations ou lorsqu'un appel téléphonique arrive ou tout simplement lorsque le téléphone n'a plus de batterie... Et ces cas de figure sont très compliqués à gérer pour nous, développeurs.
Mais que fait la police ? (Enfin Google hein !) >_<
Eh bien, au début pas grand chose... et là était tout le problème ! Les développeurs Android étaient livrés à eux-mêmes et tentaient plus ou moins d'appliquer une certaine architecture sur leur projet, respectant un maximum les bonnes pratiques de développement comme "la séparation des préoccupations" ou "separation of concerns (SoC)" en anglais : une classe = une responsabilité, une méthode = une action particulière, etc.
Certains ont même décidé de se passer de l'architecture MVC et de se lancer dans des architectures plus "propres" comme le MVP ou le MVVM. On a vu naître une architecture à part : la Clean Architecture, qui permet de séparer les différentes couches d’une application et d’appliquer une sous-architecture pour l’affichage des vues (MVP, MVVM ou autre). Vous trouverez des exemples en cliquant sur ce lien.
C'est dans ce contexte assez tendu que les équipes de Google ont décidé de sortir, à la fin de l'année 2017, un ensemble de librairies permettant de créer plus facilement des applications robustes, testables et maintenables dans le temps, qu'ils ont appelé : l'Android Architecture Components !
Quels sont les deux principes fondateurs de l'Architecture Components ?
Afin d'architecturer le mieux possible une application Android, l'Architecture Components se base sur deux principes fondateurs :
Les contrôleurs (activités ou fragments) devraient servir uniquement à manipuler l'interface graphique (création, mise à jour, etc.) et interagir avec le système d'exploitation (lancement d'une nouvelle activité par exemple). C'est tout ! Le reste du code métier doit absolument être déporté dans des classes à part.
L'interface graphique devrait être généralement mise à jour à partir d'une classe modèle (POJO), de préférence persistable, et la refléter (modélisation) le plus fidèlement possible. L'objectif est de faire face plus facilement à une perte de connexion internet ou à la destruction de votre application, en récupérant le modèle persisté directement depuis le stockage de votre téléphone (à partir d'une base de données, par exemple... ;)).
Essayez d'avoir toujours ces deux principes en tête quand vous développez une application Android, cela vous permettra naturellement de vous poser les bonnes questions en termes d'architecture.
De quels éléments se compose l'Architecture Components ?
Dans l'objectif d'alléger un maximum les contrôleurs (activités et fragments) de nos applications Android, il a fallu déporter certaines actions dans des classes dédiées. Ainsi, les équipes d'Android ont fait le choix de poser l'architecture suivante :
Le contrôleur : Votre contrôleur (activité ou fragment) sera dédié à la manipulation de votre interface graphique, ni plus, ni moins.
Le ViewModel : Le contrôleur implémentera toutefois une classe de type ViewModel, dont le rôle sera de fournir au contrôleur les données utilisées par l'interface graphique. Une des spécificités de la classe ViewModel est sa capacité à "survivre" aux changements de configuration, comme la rotation de l'écran par exemple, sans perdre ses données... :magicien:
Les LiveData : Les données présentes au sein du ViewModel seront principalement de type LiveData, type qui nous permettra "d'observer" plus facilement leurs changements tout en respectant le cycle de vie de notre application. Le type LiveData correspond en quelque sorte à la notion d'observable sous RxJava, que nous avons déjà étudiée ensemble dans un précédent cours sur la récupération et l'affichage des données distantes, à ceci près que nous n'avons pas besoin de gérer nous-même le processus de désinscription et que LiveData a été pensé pour Android et son cycle de vie. Si, en revanche, vous souhaitez continuer à utiliser RxJava plutôt que LiveData, sachez que cela est tout à fait possible ! :)
Le Repository : À l'intérieur de chaque ViewModel, nous allons retrouver une ou plusieurs classes de type Repository, un design pattern assez connu. Son rôle est un peu particulier car il nous servira de médiateur entre le ViewModel et les différentes sources de données.
Les sources de données : À l'intérieur de chaque Repository, nous aurons les différentes classes permettant d'accéder à nos données, que l'on appelle plus communément "les sources de données" (Data Sources). Par exemple, ces classes peuvent prendre la forme de DAO, comme celles que nous avons créées dans les chapitres précédents, ou encore d'interfaces de communication avec des API, comme nous avons pu le faire dans ce chapitre de cours sur l'amélioration de l'implémentation des requêtes réseaux.
Bon je sais, tout ça est un peu théorique ! D'ailleurs, il est fort probable que vous vous demandiez pourquoi il y a un niveau de découpe aussi important... En fait, sachez que plus votre code sera découpé, plus il sera modulable, testable et lisible.
Sur des mini-applications, il est vrai que le résultat n'est peut-être pas flagrant et il sera difficile de s'en rendre compte. Cependant, quand votre projet commencera à grossir et à peser quelques centaines de milliers de lignes de code, vous serez très heureux d'avoir une architecture propre et maintenable, croyez-moi... ;)
En résumé
L’Architecture Components permet de rendre notre code plus robuste, modulable, testable et lisible.
Les contrôleurs gèrent la vue, et seulement la vue ! Le reste est géré par d’autres classes.
Allez, passons aux choses sérieuses et implémentons tout cela dès le prochain chapitre, à travers notre mini-application SaveMyTrip !