Premiers pas avec Android Jetpack Compose

Julien Richer
neoxia
10 min readApr 29, 2021

--

I — Introduction

Jetpack Compose se destine à être le nouveau standard de construction d’interface graphique. Ce nouvel outil va bouleverser la façon de produire le design d’applications Android en créant une alternative aux layouts.

Une application Android classique se compose de fichiers Kotlin ou Java (les activités), qui décrivent le fonctionnement des différents écrans, couplés à des fichiers XML (les layouts), qui décrivent l’interface graphique de ces écrans. Ces derniers remplissent bien leur rôle mais posent souvent des problèmes aux développeurs. Par exemple, si Android Studio pointe la ligne où des erreurs ont été commises en Kotlin ou en Java, il ne fait qu’indiquer qu’un fichier XML contient une erreur. Charge au développeur de trouver où, ce qui peut prendre du temps et laisser un résultat incertain.

Jetpack Compose est une nouvelle boîte à outils dédiée au Material Design qui vient s’ajouter à la suite Jetpack et révolutionner la manière dont les développeurs Android construisent leurs interfaces graphiques. Ce dernier donne en effet la possibilité de remplacer complètement les layouts par une approche déclarative en Kotlin.

Le principe est plutôt simple : vous créez directement vos vues dans votre activité, les paramétrez et les positionnez, toutes au même endroit. Fini de jongler entre plusieurs fichiers pour développer et débugger l’UI !

Ces vues sont ainsi décrites dans des fonctions Composable qui seront des blocs modulaires que vous pourrez réutiliser à votre guise simplement en les appelant.

Tout au long de cet article, nous établirons des comparaisons entre la méthode Compose et la méthode classique Android afin de pouvoir en tirer des points forts ou points faibles ensuite.

II — Exemple

1 — Mise en place de l’environnement

Afin de se faire une idée de ce nouvel outil, le meilleur moyen est de l’utiliser pour développer une petite application en utilisant les différentes possibilités qu’il nous propose. Je me suis donc essayé à développer un Pokédex avec Compose.

Avant de commencer à vous décrire l’exemple sur lequel j’ai travaillé, je dois vous avertir que Jetpack Compose est encore en version bêta et n’est donc pas encore disponible sur Android Studio. Pour pouvoir vous faire la main sur cet outil, vous devrez télécharger Android Studio Canary, la version qui vous permet de jouer avec toutes les mises à jour encore en alpha ou bêta.

Si vous avez envie de vous y mettre, cliquez ici pour le set-up puis le tuto officiel est là.

2 — Création d’une vue

Vous allez construire votre UI directement dans l’activité, en vous plaçant dans le onCreate. De la même manière que le setContentView qui faisait le lien avec le layout, c’est la méthode setContent qui va gérer l’interface graphique de l’écran :

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// C’est ici que ça se passe !
}
}

a — Texte

Commençons avec la vue la plus simple : un texte.

@Composable
fun NameCard(name: String) {
val typography = MaterialTheme.typography
Text(text = name, color = Color.White, style = typography.h6)
}

On crée ainsi l’équivalent d’un TextView en lui donnant un texte, une couleur de texte et un style. Notez au passage que vous avez directement accès à MaterialTheme , un thème Material Design qui vous fournit plus d’une dizaine de styles pour vos textes.

Le détail important ici est que la fonction qui crée ce texte a l’annotation @Composable qui signifie qu’elle décrit l’UI de notre activité.

b — Image

Pour les images, c’est la même chose avec des paramètres différents :

@Composable
fun ImageCard(imageId: Int) {
Image(
asset = imageResource(imageId),
modifier = Modifier
.preferredHeight(CARD_HEIGHT)
.fillMaxWidth()
)
}

On aborde ici le paramètre modifier présent sur toutes les vues qui permet de régler tout ce qui n’est pas spécifique au type de vue en question, par exemple ici les dimensions. fillMaxWidth est l’équivalent en version layout de android:layout_width="match_parent" et la méthode imageResource, quant à elle, de getDrawable.

Il ne reste qu’à appeler ces fonctions dans setContent pour afficher le texte :

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ImageCard(R.drawable.pikachu)
NameCard(“Pikachu”)
}
}

La force de Compose, et là d’où il tient son nom, est que nous allons pouvoir ”composer” notre interface graphique à l’aide de fonctions Composable qui sont des briques parfaitement réutilisables. Cet aspect modulaire est extrêmement appréciable comparé aux layouts.

3 — Organisation des vues entre elles

Compose propose des structures simples similaires au LinearLayout pour organiser les vues : les lignes Row et les colonnes Column. Vous pouvez directement y créer des vues ou appeler des fonctions Composable et les éléments se rangeront d’eux-mêmes.

Par exemple on peut simplement disposer nos vues précédemment créées dans une colonne :

setContent {
Column(
modifier = Modifier.padding(8.dp)
) {
ImageCard(R.drawable.pikachu)
NameCard(“Pikachu”)
}
}

4 — Structures plus complexes

Malheureusement Compose ne propose pas encore de réel équivalent au RecyclerView, ce qui est une grosse lacune… Mais tout n’est pas perdu, il existe néanmoins des structures qui s’en approchent : LazyColumn et LazyRow. Ces dernières permettent en effet d’aligner verticalement ou horizontalement des éléments provenant d’une liste passée en paramètre.

On peut ainsi remplacer un RecyclerView en créant une colonne de lignes :

@Composable
fun PokemonGrid(pokemons: List<Pokemon>) {
val chunkedPokemons = pokemons.chunked(NB_POKEMONS_PER_ROW)
LazyColumnFor(items = chunkedPokemons) { rowItems ->
Row {
rowItems.forEach { item ->
PokemonCard(item)
}
}
}
}

La fonction chunk permet de découper une liste en liste de sous-listes de longueur donnée, idéale donc dans notre exemple. On la passe en paramètre à LazyColumnFor puis, pour chaque élément, on récupère une sous-liste qui nous permet de remplir une Row.

(Ici on n’a pas utilisé de LazyRow pour éviter que les lignes ne se scrollent)

5 — Résultat

Et voici l’humble résultat de ces premiers pas avec Jetpack Compose…

… qui est très largement inspiré du projet de Zsoltk, plus abouti, dont voici un aperçu.

III — Avantages

1 — Single Source Of Truth (SSOT)

Compose repose sur la philosophie SSOT, c’est-à-dire : toute donnée ne doit être stockée et modifiée qu’à un seul endroit dans le but de ne jamais se retrouver dans une situation discordante où deux variables censées représenter la même information sont différentes. La plus-value se fait particulièrement ressentir lors de la maintenance et du debugging de l’application.

2 — La Fin des layouts

Un second avantage que nous avons déjà rapidement évoqué est la disparition totale des layouts. Peut-être que vous ne réalisez pas le bien que cela représente alors voici une petite explication.

Dans le développement classique d’une UI en Android, vous décrivez une grande partie de celle-ci dans un fichier XML à part, le layout, qui va être couplé à l’activité en Kotlin ou Java. Celle-ci le lira, comme une liste d’instructions, pour construire l’interface graphique. En revanche, des situations communes nécessitent de récupérer depuis l’activité, via leurs identifiants, les vues définies dans le layout pour effectuer des opérations dessus. Par exemple pour ajouter un événement lors d’un clic ou ajuster sa taille avec le résultat d’un savant calcul.

On économise aussi la création de fichiers drawable XML pour créer des backgrounds customs.

3 — Un Futur standard

Google ne cache pas que Compose a pour vocation de devenir le nouveau standard en matière de développement d’UI pour Android. Même si ce framework n’est toujours qu’en bêta aujourd’hui (Avril 2021), ses créateurs pensent déjà aux futures migrations que les développeurs Android devront faire lors de sa sortie en version stable. Le point important à noter est que Compose est tout à fait compatible avec la manière actuelle de procéder et que rien ne vous forcera à basculer votre application d’un coup. Certains se sont déjà amusés à franchir le pas en migrant écran par écran leurs apps afin de voir par eux-mêmes si cela fonctionne bien comme on le prétend. Et… A priori ça fonctionne !

NB : De plus, la migration ne devrait pas non plus bouleverser la version minimum de sdk gérée par votre application car Compose ne requiert que Android 5.0 Lollipop, qui représente plus de 94% des appareils sous Android.

IV — Des Performances prometteuses

Cette section se base sur l’article très complet de Chris Bane, développeur Android chez Google qui fait partie de ces joyeux lurons qui ont déjà migré leur application avant la release officielle du toolkit.

Voici quelques graphiques tirés de cet article qui illustrent quelques données intéressantes, à chaque fois l’avant, pendant et après migration vers Compose.

1 — Taille de l’apk

En supprimant les layouts et les anciennes librairies UI comme AppCompat, on réduirait la taille des APKs de 40%.

2 — Nombre de méthodes

On aurait aussi une diminution du nombre d’appels de fonctions de 17%.

3 — Nombre de lignes de code

Sans les layouts, il ne resterait que 24% des fichiers XML sans pour autant augmenter la quantité de code ! Probablement parce qu’on s’épargne le boilerplate lié aux layouts.

4 — Temps de build

Actuellement, on ne note pas d’impact significatif sur le temps de build de l’application. On aurait pu légitimement craindre une augmentation de celui-ci parce qu’a priori on a plus de calculs à faire pour générer les vues.

V — Inconvénients

Malgré mon enthousiasme que vous devinez sûrement depuis le début de cet article, tout n’est pas aussi rose que je vous l’ai laissé croire jusqu’à maintenant. Compose souffre de quelques défauts qui laissent un arrière goût amer malgré tout.

1 — Un Futur encore lointain

Première chose, nous n’avons aucune date de sortie prévue, on n’en est qu’à la bêta donc la première release stable ne sera sûrement pas pour demain.

2 — Le Manque de documentation

Pour rédiger ce modeste article, je me suis bien sûr essayé à la tâche d’utiliser le toolkit pour développer une petite application : dans un premier temps les choses semblent instinctives, mais dès qu’on bloque, on souffre de l’absence quasi-totale de documentation officielle. Et ne comptez pas sur StackOverflow cette fois-ci ! Certes on y trouve déjà un certain nombre de threads, mais la plupart devient obsolète et inutilisable en quelques mois car les mises à jour sont très fréquentes.

3 — Que des éléments simples

Actuellement Compose ne propose que des éléments (texte, image, bouton, etc) et des structures simples (ligne, colonne) mais dès que vous voulez à peine compliquer les choses, c’est à vous de réinventer la roue. C’est agaçant de devoir recréer le principe de grille…

4 — Des fonctionnalités de base absentes

Un autre point qui peut sembler anecdotique mais qui m’a heurté, c’est que seuls les boutons sont cliquables. Dommage, cela force à ajouter un élément supplémentaire juste pour gérer le clic.

5 — Le Principe d’état

Même si nous n’en avons pas parlé jusqu’à maintenant, je pense que la vraie difficulté pour prendre en main sérieusement Compose réside dans ce changement de philosophie. Il n’est plus question de récupérer l’instance d’une vue pour effectuer des opérations dessus lorsque vous en avez envie.

En effet, une des spécificités majeures de ce nouvel outil est que l’affichage se rafraîchit de lui-même sans que vous n’ayez à intervenir. Pour cela, chaque vue se gère elle-même et va automatiquement se mettre à jour lorsque son état change.

Il faut donc décrire à l’avance les différents états possibles de votre vue et, selon celui-ci, adapter l’affichage dans la fonction Composable qui lui est associée.

Je n’ai été confronté à ce principe que pour 2 fonctionnalités dans ma petite application :

  • Afficher et faire disparaître un Dialog
  • Déclencher et arrêter une animation

Alors que ces 2 exemples me semblent triviaux, c’est encore loin d’être évident et spontané pour moi en “version Compose”.

VI — Bilan

Les Plus

+ À l’usage, Compose se révèle confortable et plutôt instinctif

+ Le code écrit pour définir les vues est bien plus lisible qu’un layout qui devient vite difficile à déchiffrer

+ Le rythme soutenu de mises à jours et corrections est encourageant, ce n’est pas un petit projet à la marge

+ Le système est compatible avec les layouts, ce qui facilitera la future migration

+ De grosses ressemblances avec SwiftUI, côté iOS, donc moins d’apprentissage pour maîtriser les deux !

Les Moins

- Nous n’avons pas la moindre idée de la date de sortie

- Le principe d’état des vues est déroutant : ça va demander du travail pour s’y habituer

- La boîte à outils n’est pas encore complète, il manque des choses qui me semblent indispensables (comme la grille)

- L’onglet de preview qui vous affiche ce que vous êtes en train de coder est censé pouvoir être interactif (pouvoir cliquer, scroller, etc) mais personnellement cela n’a jamais fonctionné chez moi…

Le mot de la fin

Ce qui est certain, c’est que les développeurs Android devront bien s’y atteler un jour car Jetpack Compose sera à terme le nouveau standard. Profitons du temps qu’il nous reste avant la release officielle pour commencer à s’y intéresser, même de loin, afin de rendre la transition moins abrupte lorsqu’elle viendra !

Et vous, avez-vous déjà pu essayer Compose ? Qu’en avez-vous pensé ?

N’hésitez pas à partager votre avis ou votre expérience dans les commentaires !

--

--