La couche de données, via les dépôts, la base de données et les entités, est en place ! Vous pouvez maintenant vous attaquer à la couche interface utilisateur.
Ajoutez un conteneur d’état (ViewModel)
Cette couche contient en réalité deux éléments :
Le conteneur d'état qui contient des données, qui gère la logique métier et qui expose les données à l’interface graphique. C’est le ViewModel.
L’interface graphique qui affiche les données à l'écran à l’aide de XML ou Jetpack Compose. C’est la View.
Dans le cadre de l’application PETiSoin, vous allez devoir créer un premier ViewModel, associé au premier écran de l’application qui permet de lister et de récupérer l’ensemble des animaux présents dans la base de données. Pour ce faire, vous devez suivre ces étapes.
Créez votre premier ViewModel
Créez une classe
MainActivityViewModel
, qui hérite de la classeViewModel
, dans un package ui.home.Passez-lui au sein de son constructeur le dépôt
AnimalsRepository
.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
Ajoutez des annotations
Dès ce stade, il est possible de décorer le code à l’aide de deux annotations.
La première est l’annotation
@Inject
, au niveau du constructeur, pour indiquer à Hilt qu’il est chargé d’injecter le dépôt dans le ViewModel.La seconde annotation est
@HiltViewModel
, sur la classeMainActivityViewModel
qui permet à Hilt de reconnaître la classe ViewModel pour lui fournir automatiquement les dépendances nécessaires.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
Récupérez l’ensemble des données en Java
Dans le cadre de la version Java, vous pouvez créer une méthodegetAllAnimals
qui retourne simplement le résultat de la méthodegetAllAnimals
de la classeAnimalsRepository
.
@HiltViewModel
public final class MainActivityViewModel
extends ViewModel
{
//...
public LiveData<List<Animal>> getAnimals()
{
return animalsRepository.getAllAnimals();
}
}
Récupérez l’ensemble des données en Kotlin
En Kotlin, il est possible de créer un attributanimal
qui est unStateFlow
et qui renvoie le résultat de la méthodegetAllAnimals
de la classeAnimalsRepository
. Cependant, puisque cette méthode renvoie un Flow
, vous devez utiliser la méthode stateIn
pour convertir leFlow
enStateFlow
. Cette méthode attend trois paramètres :
la portée de la coroutine : vous pouvez utiliser l’attribut
viewModelScope
disponible dans leViewModel
;la valeur initiale : vous pouvez renseigner une liste vide ;
la stratégie de démarrage et d’arrêt du partage du Flow : vous pouvez utiliser
SharingStarted.WhileSubscribed(5000)
.
Euh… C’est quoi ce morceau de code ?
La fonctionWhileSubscribed
indique que leFlow
ne démarre l'émission de valeurs que lorsqu'il y a au moins une souscription. Lorsqu’il n’y a plus de souscriptions, l’émission est alors arrêtée après un certain délai. Dans le cas du code proposé, le délai est de 5000 millisecondes soit 5 secondes. Ces 5 secondes, qui s’apparentent à un nombre magique, permettent notamment au flux de survivre à un changement de configuration.
@HiltViewModel
class MainActivityViewModel @Inject constructor(animalsRepository: AnimalsRepository) : ViewModel() {
val animals = animalsRepository.getAllAnimals().stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
}
Affichez les données de Room dans une View
Maintenant que le ViewModel est en place, continuons d’implémenter la couche interface utilisateur en ajoutant le second élément, à savoir l’interface graphique (ou la View). Elle va nous permettre d’afficher à l’écran les données que nous avons stockées dans la base de données Room.
Créez le layout XML d’une liste
Comme vous le savez, le but de l’écran est d’afficher l’ensemble des animaux au sein d’une liste et donc d’uneRecyclerView
. Pour ce faire, suivez ces étapes.
Ouvrez le fichier "activity_main.xml" du projet.
Modifiez son contenu pour répondre à notre objectif.
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:context=".MainActivity"
/>
Créez le layout XML d’une cellule
Une liste est composée de cellules. La prochaine étape consiste donc à écrire le layout d’une cellule. Dans le cas de notre application PETiSoin, une cellule doit afficher les informations suivantes liées à chaque animal :
L’identifiant ;
Le type ;
La race.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="8dp"
>
<TextView
android:id="@+id/id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="@tools:sample/first_names"
/>
<TextView
android:id="@+id/type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="@tools:sample/first_names"
/>
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="@tools:sample/first_names"
/>
</LinearLayout>
Créez l’adaptateur
Puisqu’unAdapter
doit obligatoirement être associé à uneRecyclerView
, vous devez créer une classeAnimalsAdapter
dans le package ui.home.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
Complétez l’activité
Tout est maintenant prêt pour compléter la classeMainActivity
avec le code écrit jusqu’à maintenant. Avant de commencer, vous devriez avoir une classe qui ressemble à ça.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
1. La première étape est d’injecter le ViewModel dans l’activité grâce à Hilt. Pour faciliter l’injection des dépendances dans les classes Android, vous devez aider Hilt à identifier l’activité comme un composant Android en ajoutant l’annotation@AndroidEntryPoint
sur la classe.
2. Obtenez une instance de ViewModel.
En Java, vous devez créer une instance de manière classique à l'aide de la classe ViewModelProvider
. En Kotlin, il est possible d’utiliser l’extensionby viewModels
.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
3. L’étape suivante est d’ajouter une instance de la classeAnimalsAdapter
en tant qu’attribut de l’activité et de l’attacher à laRecyclerView
pour afficher les données.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
4. La dernière étape consiste à observer en temps réel les animaux, que ça soit via les LiveData
en Java ou via lesFlow
en Kotlin, afin de détecter les changements et mettre à jour laRecyclerView
.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
Voici une vidéo qui récapitule les principales étapes pour concevoir la couche interface utilisateur.
À vous de jouer
Contexte
Il est temps de créer votre premier écran de l’application PETiSoin qui respecte la patron de conception MVVM.
Consignes
Dans le projet, disponible sur GitHub (Java ou Kotlin), vous devez créer un nouvel écran, via une nouvelle activité, qui permet de lister l’ensemble des vaccins d’un animal. Ce nouvel écran est accessible après avoir cliqué sur un animal listé sur l’écran principal de l’application.
Livrables
Vous pouvez dupliquer le projet GitHub pour modifier le code source du projet et fournir un projet dont l’ensemble des tests passe.
En résumé
Le ViewModel joue le rôle de conteneur d’état de la couche d’interface utilisateur.
Un ViewModel hérite de la classe
ViewModel
mise à disposition par Google.Le ViewModel délègue la récupération des données à un repository.
Le ViewModel peut exposer des flux qui peuvent être observés dans la View.
La View permet de restituer graphiquement les données aux utilisateurs de l’application.
Il ne nous reste plus qu’à vous souhaiter bonne chance pour la suite de vos aventures en tant que développeur Android !
Nous espérons que ce cours vous aura apporté toutes les bases nécessaires à la conception d’une base de données locale dans une application Android native. Votre objectif aura été, ici, de permettre une expérience 100% hors-ligne à vos utilisateurs. Dans le développement logiciel et tout particulièrement dans le développement mobile, les choses évoluent très vite. Restez alors actif sur votre veille pour rester à la page sur vos connaissances.