Introduction aux Android Architecture Components

Annoncées pendant la Google I/O 2017 (source), les Android Architecture Components (AAC) sont des librairies qui se veulent révolutionnaires. La première version stable publiée date de novembre 2017 (source). Nous allons tout d'abord vous expliquer leurs origines.

Constat

À l’instar du développement Web et a contrario d’iOS, l’écosystème d’Android est très fragmenté. Tout d’abord, en termes d’interfaces. En effet, la plateforme est opensource et donc personnalisable. Les constructeurs n’ont pas hésité à développer leur propre surcouche afin de se distinguer de leurs concurrents :

miui-3

Ci-dessus : MIUI 8 (source)

android_stock

Ci-dessus : Android 7 (quasiment stock) (source)

De la même manière, les versions de la plateforme Android sont diverses et variées :

repartition_android_04_2018

Ci-dessus : Répartition des terminaux Android par version (Avril 2018 - source)

Vous l’avez deviné : c’est exactement le même constat pour les librairies et frameworks. Au final, ces contraintes complexifient le développement. Il ne faut d’ailleurs pas oublier que les nouvelles versions publiées chaque année viennent pimenter le tout.

Prise de position

android_enterprise_recommended-3

Cela fait longtemps que Google est conscient de ce problème. Depuis l’année dernière, l’entreprise a décidé d’affirmer de manière plus prononcée sa volonté de le résoudre. Nous pouvons relever trois faits marquants à ce sujet :

  • Le lancement d’un nouveau programme en février 2018 : Android Enterprise Recommended (source). Le but est d’assurer des mises à jour régulières sur les terminaux ;
  • Project Treble, lancé avec Android 8.0. Il favorise aussi les mises à jour des périphériques Android (source) ;
  • La release des AAC (Android Architecture Components).

Solutions apportées par les AAC

La volonté de Google est de fournir des outils maintenus activement et répondant à certaines problématiques essentielles du développement Android. À savoir, gérer efficacement :

  • La persistance des données ;
  • Les cycles de vie de l’application ;
  • La communication entre l’UI et les données.

Ces nouveaux composants solutionnent non seulement ces problématiques, mais sont également complémentaires les uns par rapport aux autres. C’est ce que nous allons voir maintenant.

Components

Cinq nouvelles librairies ont été ajoutées via la publication des AAC. Nous allons vous présenter leurs avantages et complémentarités.

Lifecycles

Le but de cette librairie est de pouvoir créer des composants lifecycle-aware. Littéralement, cela signifie qu’ils sont conscients du cycle de vie de leur contexte d’exécution. Le premier composant est le Lifecycle. Voici ses états (source) :

etats_lifecycle

Ci-dessus : États d’un Lifecycle (source)

Le second est le LifecycleOwner. Comme son nom l’indique, il possède un Lifecycle. Le LifecycleOwner publie les différents états de son Lifecycle. Enfin, le dernier est le LifecycleObserver qui observe les états de l’owner.

L’intérêt de cette relation observable / observer est d’éviter les fuites mémoires et les erreurs, en particulier lorsqu’on exécute des tâches en arrière-plan.

Vous utilisez régulièrement et sans le savoir des composants lifecycle-aware. En effet, les Activités et Fragments sont des LifecycleOwner. Ils possèdent chacun leurs callbacks liés aux changements d'états de leur cycle de vie. Rappelez-vous de ce schéma lors de vos débuts sur Android :

cycle_vie_act

Ci-dessus : Cycle de vie d'une Activité (source)

La prochaine librairie s’interface justement à merveille avec le cycle de vie d’un Fragment ou d’une Activité.

LiveData

Ce deuxième composant est un data holder amélioré :

  • Il est lifecycle-aware ;
  • Il est observable ;
  • Il ne publiera des données que si le LifecycleOwner associé est actif ;
  • Si le LifecycleOwner est détruit, les observers associés sont automatiquement détruits ;
  • Il gère parfaitement les changements de configuration tel que le changement d’orientation du téléphone.

On crée en général des LiveData dans un ViewModel. C’est ce que nous allons vous expliquer maintenant.

ViewModel

Un controller UI tel qu’un Fragment ou une Activité peut être détruit ou recréé par le framework Android. Cela se fait en réponse à des événements provoqués ou non par l’utilisateur. L’exemple le plus simple auquel on peut penser est le changement d’orientation. Si on ne le prévoit pas, on perd toutes les données associées. On doit donc :

  • Soit systématiquement récupérer les données ;
  • Soit utiliser les méthodes offertes par Android pour sauvegarder des données telles que onSaveInstanceState(). Problème : c’est une solution fastidieuse et peu adaptée aux données de taille conséquente.

ViewModel vient offrir une solution out of the box. Une fois n’est pas coutume, étudions son cycle de vie :

view_model

Ci-dessus : Cycle de vie d'un ViewModel (source)

En fait, un ViewModel est lifecycle-aware. Si son LifecycleOwner est une activité, il ne sera détruit qu’au moment où cette dernière sera finie et détruite. Exit les problèmes liés au changement d’orientation ! Vous l’aurez compris, c’est la place idéale pour notre (live) data. De plus, son exécution étant décorrélée de l’activité, on peut instancier un seul et même ViewModel, partagé par plusieurs UI Components !

Ci-dessous, un résumé des interactions et possibilités offertes par ces 3 premiers composants :

resume-3

En l’état, on ne manipule que des données en mémoire vive. On va pouvoir interagir avec une base de données via Room.

Room

Enfin ! Google propose sa propre implémentation pour interagir avec une base de données sur Android. On pouvait commencer à se perdre entre :

  • Les librairies SQLite fonctionnelles, mais plus maintenues (ActiveAndroid) ;
  • Les librairies proposant leur propre SGBD à la place de SQLite, qui est de base dans Android (Realm).

Room est une librairie qui permet de manipuler les données d’une base SQLite. Elle est décomposée en trois parties :

  1. Les Entities qui correspondent à des tables en base de données ;
  2. Les DAOs qui contiennent les méthodes permettant d’interagir avec la base de données ;
  3. La Database, où on déclare (entre autres) nos DAOs, nos Entities et la version de la base.

room-1

Ci-dessus : Fonctionnement de Room (source)

Dans Room, les déclarations se font par le biais d’annotations. Bonus : elles sont vérifiées à la compilation. Bien sûr, Room peut renvoyer des LiveData. Dans ce cas, lors de chaque modification de la base, l’objet LiveData est automatiquement mis à jour avec les dernières données !

Dans le but de préserver les performances de vos applications, Room interdit les manipulations de la base dans l’UI thread. Une exception au runtime est déclenchée en cas d’utilisation forcée.

Le dernier composant va vous permettre d’éviter des ralentissements lorsque vous manipulez de gros volumes de données.

Paging

Lister plusieurs centaines (ou milliers) d’éléments est une problématique courante. Comment garantir les performances de notre application ? Comment éviter de multiplier les requêtes ?

Auparavant dans Android, nous avions deux solutions :

  1. CursorAdapter. Problème : les requêtes sont effectuées dans l’UI thread ;
  2. AsyncListUtil. Problème : c’est assez peu configurable. (source)

La librairie Paging a été créée pour résoudre ces deux problèmes. Tout d’abord, elle se base sur une mécanique de dataflow qui s’exécute en arrière-plan :

paging

Ci-dessus : Fonctionnement du dataflow de Paging (source)

Quand une PagedList est créée à partir d’une Datasource, elle est retournée au PagedListAdapter. Ce dernier calcule via un DiffUtil les différences entre la liste courante et la nouvelle. Tout cela est fait en arrière-plan. Puis, la View est notifiée qu’il y a eu un changement. Elle se met finalement à jour en conséquence dans l’UI thread.

De plus, elle offre des options intéressantes :

  • Possibilité de définir la règle du next element ;
  • Définition du nombre d’éléments à charger en mémoire ;
  • Définition des callbacks sur de nombreux événements : (insertion de données, fin du chargement, etc.).

Bien sûr, les composants de Paging sont compatibles avec Room et LiveData :)

Conclusion

Avec ces nouveaux composants, Google offre aux développeurs une architecture structurée et assez complète, mise en avant (entre autres) sur leur site.

Bien que récente, elle apporte de nombreux avantages et permet d'éviter les erreurs classiques sur Android, sous la forme de Best Practices.
Nous ne manquerons pas dans un prochain article d'aborder la partie pratique, via la création d'une application 100% AAC ;)

Sources