18/02/2021 18/02/2021
Concept de base
Avant d’aborder comment implémenter une base de données
Room sous android :
Persistance de données Architecture MVVM
ZEMALI Elamine
Introduction Model-View-ViewModel Theory
Plusieurs support de stockage de données existent. MVVM signifie Model-View-ViewModel.
MVVM est un modèle architectural dont le but principal est
Android et SqLite de parvenir à la séparation des préoccupations grâce à une
distinction claire entre les rôles de chacune de ses couches:
View affiche l’interface utilisateur et informe les autres couches
Room database
sur les actions des utilisateurs.
ViewModel expose les informations à la vue.
Le modèle récupère les informations de votre source de
données et les expose aux ViewModels.
1 2
18/02/2021 18/02/2021
Différence entre MVVM ET MVC Le modèle
La principale différence entre MVVM et ces modèles est Dans Android, vous créez généralement des modèles en tant
qu’il y a un fort accent que le ViewModel ne doit pas que classes de données,
contenir de références aux vues. Une application qui affiche des informations sur les derniers
Le ViewModel ne fournit que des informations et il n’est pas films. Vous créeriez sûrement une classe de film qui contient
intéressé par ce qui le consomme. des données telles que le titre, la description, l’heure et la
date de sortie du film.
Le modèle ViewModel
Le viewModel a comme mission :
Connu sous le nom de DataModel.
récupère les informations nécessaires à partir du modèle,
Il est chargé d’exposer les données pertinentes à vos
applique les opérations nécessaires
ViewModels d’une manière facile à consommer. expose toutes les données pertinentes pour les vues.
Il doit également recevoir tous les événements du Traite le problème des données perdues lors d’une re-
ViewModel dont il a besoin pour créer, lire, mettre à jour Creation.
ou supprimer toutes les données nécessaires du backend.
3 4
18/02/2021 18/02/2021
ViewModel La vue
survivre aux changements de configuration/cycle de vie La vue informe également ViewModels sur les actions des
comme les rotations d’écran. utilisateurs.
exposer les événements que les vues peuvent observer et Les vues peuvent avoir une référence à un ou plusieurs
réagir en conséquence ViewModels, mais ViewModels ne peut jamais avoir
d’informations sur les vues.
vous communiquerez généralement les données entre les
vues et les viewmodels avec observables, en utilisant des
bibliothèques telles que RxJava, LiveData ou DataBinding.
La vue Avantages de MVVM
La vue est responsable de l’affichage de l’interface. les tests unitaires deviennent très faciles car ils n’ont aucune
elle est généralement représentée dans Android sous forme référence aux vues.
d’activités ou de fragments. MVVM résout le problème de « ou mettre ce code » en
Son rôle principal dans le modèle MVVM est d’observer un fournissant une meilleure séparation des préoccupations.
ou plusieurs ViewModels pour obtenir les informations L’ajout de ViewModels, dont le but principal est d’être
nécessaires dont il a besoin et mettre à jour l’interface complètement séparé des vues, réduit le risque d’avoir trop
utilisateur en conséquence. de code dans les autres couches.
5 6
18/02/2021 18/02/2021
Implémenter un viewmodel Implémenter un viewmodel
ViewModel est responsable de la préparation des données accéder à la liste
pour l’interface utilisateur.
Les objets ViewModel sont automatiquement conservés lors public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
des modifications de configuration afin que les données qu’ils // Create a ViewModel the first time the system calls an activity's onCreate() method.
détiennent soient immédiatement disponibles pour l’activité // Re-created activities receive the same MyViewModel instance created by the first
activity.
ou fragment.
MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
Implémenter un viewmodel Implémenter un viewmodel
Par exemple, Attention : Un ViewModel ne doit jamais faire référence à
une vue, à un cycle de vie ou à une classe qui peut contenir
public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
une référence au contexte d’activité.
public LiveData<List<User>> getUsers() { Si le ViewModel a besoin du contexte d’application, par
if (users == null) {
users = new MutableLiveData<List<User>>(); exemple pour trouver un service système, il peut étendre la
loadUsers(); classe AndroidViewModel et avoir un constructeur qui reçoit
}
return users;
l’application dans le constructeur, puisque la classe
} Application étend le contexte.
private void loadUsers() { Les objets ViewModel peuvent contenir lifecycleObservers,
// Do an asynchronous operation to fetch users. tels que les objets LiveData.
}
}
7 8
18/02/2021 18/02/2021
LiveData Utiliser LiveData
LiveData est une classe observable de détenteurs de données. Suivez ces étapes pour travailler avec des objets LiveData :
1-Créez une instance de LiveData pour conserver un certain type de
LiveData ne met à jour que les observateurs des composants données. Cela se fait généralement dans votre classe ViewModel.
de l’application qui sont en état de cycle de vie actif. 2-Créez un objet Observer qui définit la méthode onChanged() qui
LiveData considère qu’un observateur, qui est représenté par contrôle ce qui se passe lorsque les données détenues par l’objet
LiveData changent.
la classe Observer , est dans un état actif si son cycle de vie
Vous créez généralement un objet Observe dans un contrôleur
est dans l’état STARTED ou RESUMED. d’interface utilisateur, tel qu’une activité ou un fragment.
Cette relation permet à l’observateur d’être supprimé 3- Attachez l’objet Observer à l’objet LiveData en utilisant la
lorsque l’état de l’objet du cycle de vie correspondant se méthode observe() . La méthode observe () prend un objet
LifecycleOwner. Cela souscrit à l’objet Observer à l’objet
modifie en DESTROYED. LiveData afin qu’il soit informé des modifications. Vous attachez
généralement l’objet Observer dans un contrôleur d’interface
utilisateur, comme une activité ou un fragment
Avantage de LiveData Etape 1 créer LiveData
s’assure que votre interface utilisateur correspond à votre LiveData est un conteneur (wrapper) qui peut être utilisé
état de données. avec n’importe quelle donnée, y compris les objets qui
Aucune fuite de mémoire implémenter des collections, telles que List.
Aucun bug dû à l’arrêt des activités Un objet LiveData est généralement stocké dans un objet
Modifications de configuration appropriées ViewModel qui est accessible via une méthode getter
Partage de ressources
9 10
18/02/2021 18/02/2021
public class NameActivity extends AppCompatActivity {
Exemple : exemple:
private NameViewModel model;
public class NameViewModel extends ViewModel {
@Override
protected void onCreate(Bundle savedInstanceState) {
// Create a LiveData with a String
super.onCreate(savedInstanceState);
private MutableLiveData<String> currentName;
model = new ViewModelProvider(this).get(NameViewModel.class);
public MutableLiveData<String> getCurrentName() {
if (currentName == null) {
final Observer<String> nameObserver = new Observer<String>() {
currentName = new MutableLiveData<String>();
@Override
}
public void onChanged(@Nullable final String newName) {
return currentName;
nameTextView.setText(newName);
}
}
};
// Rest of the ViewModel...
model.getCurrentName().observe(this, nameObserver);
}
}
}
Observe LiveData Update LiveData objects
la méthode onCreate () est le bon endroit pour observer un LiveData vs MutableLiveData
objet LiveData. LiveData n’a pas de méthodes accessibles au public pour
LiveData ne fournit des mises à jour que lorsque les données mettre à jour les données stockées.
changent, et uniquement aux observateurs actifs. La classe MutableLiveData expose publiquement les
méthodes setValue(T) et postValue(T).
11 12
18/02/2021 18/02/2021
Update LiveData objects Room database
Exemple Entité: lorsque vous travaillez avec des composants d'architecture, l'entité
est une classe annotée qui décrit une table de base de données.
Base de données SQLite: sur l'appareil, les données sont stockées dans une
base de données SQLite.
DAO: objet d'accès aux données. Un mappage des requêtes SQL aux
button.setOnClickListener(new OnClickListener() { fonctions, Dans l’utilisation standard de SQLite, l’utilisateur devait
@Override écrire toutes les requêtes en langage SQL (en
public void onClick(View v) { appelant SQLiteOpenHelper). Lorsque vous utilisez un DAO, vous
String anotherName = "John Doe"; appelez les méthodes et les composants s'occupent du reste.
model.getCurrentName().setValue(anotherName);
}
Base de données room:couche de base de données au-dessus de la base de
});
données SQLite qui prend en charge les tâches standards. Elle Fournit
un stockage de données local plus facile. La base de données Room
utilise le DAO pour envoyer des requêtes à la base de données SQLite.
Room database Room database
Repository: classe que vous créez pour gérer plusieurs sources de
données
ViewModel : fournit des données à l'interface utilisateur et sert de
centre de communication entre le Repository et l'interface
utilisateur. Les instances deViewModel survivent aux
modifications de configuration de l'appareil.
LiveData : classe de détenteur de données qui suit le modèle
d’observateur, ce qui signifie qu'il peut être observé. Le liveDate
contient toujours en cache la dernière version des données
et avertit ses observateurs lorsque les données sont
modifiées. LiveData gère automatiquement l'arrêt et la reprise de
l'observation, car il est au courant des changements d'état du cycle
de vie pertinents.
13 14
18/02/2021 18/02/2021
Implémentation Annotations d'entité
1 Importer les bibliothèques dans Fichiers Gradle informations qui relient le contenu de la classe Java de l'entité à ce
que vous voulez représenter dans la table de base de données.
2 créer les entités avec annotations annotations couramment utilisées:
3 Créer les DAO. @Entity (tableName = "word_table" ) Chaque instance
de @Entity représente une entité dans une table. Spécifiez le nom de
4 Créer la classe de la base de donnée Room la table si vous souhaitez qu'il soit différent du nom de la classe.
@PrimaryKey Chaque entité a besoin d'une clé
5 Créer le Repository.
primaire. Pour générer automatiquement une clé unique pour chaque
6 Créer le ViewModel entité, ajoutez l’annotation (@PrimaryKey) et comme attribue
« autoGenerate = true »
7 Créer les Views @NonNull Indique qu'un paramètre, un champ ou une valeur de
retour de méthode ne peut jamais être null .
@ColumnInfo (name = "word" ) Spécifiez le nom de la colonne
dans le tableau, si vous souhaitez que le nom de la colonne soit
différent du nom de la variable dans votre classe.
Une entité est une classe qui représente une ligne dans la Exemple
table;
Par exemple, une personne, avec un identifiant unique, un @Entity
prénom, un nom de famille, une adresse e-mail public class Person {
@PrimaryKey (autoGenerate=true)
private int uid;
@ColumnInfo(name = "first_name")
private String firstName;
public class Person {
private int uid; @ColumnInfo(name = "last_name")
private String firstName; private String lastName;
private String lastName;
} // Getters and setters are not shown for brevity,
// but they're required for Room to work if variables are private.
}
15 16
18/02/2021 18/02/2021
Le DAO (objet d'accès aux données) Base de données Room
Pour accéder aux données de votre application. Room est une couche de base de données au-dessus d'une base de
données SQLite.
Chaque DAO comprend des méthodes qui offrent un accès
Room prend en charge les tâches de gestion d’une base de
abstrait à la base de données. données.
Annoter la classe par « @DAO » pour spécifier des requêtes Pour utiliser Room:
SQL et les associer à des appels de méthode. Créez une classe abstraite publique qui étend RoomDatabase.
Le DAO doit être une interface ou une classe abstraite. Utilisez des annotations pour déclarer les entités de la base de
données et définir le numéro de version.
Les requêtes courantes, les bibliothèques sont Utilisez le générateur de base de données de Room pour créer la base
: @Insert , @Delete , @Update et @Query de données si elle n'existe pas.
Ajoutez une stratégie de migration pour la base de données. Lorsque
vous modifiez le schéma de la base de données, vous devrez mettre à
jour le numéro de version et définir comment gérer les migrations.
@Dao
public interface WordDao {
// The default action is ABORT.
@Insert(onConflict = OnConflictStrategy.REPLACE)
Room fournit des vérifications au moment de la compilation des
void insert(Word word);
instructions SQLite.
@Update Par défaut, pour éviter de mauvaises performances de l'interface
public void updateWords(Word... words); utilisateur, Room ne vous permet pas d'émettre des requêtes de
// Simple query that does not take parameters and returns nothing.
base de données sur le thread principal. LiveData applique cette
@Query("DELETE FROM word_table") règle en exécutant automatiquement la requête de manière
void deleteAll(); asynchrone sur un thread d'arrière-plan, si nécessaire.
En règle générale, vous n'avez besoin que d'une seule instance de
// Simple query without parameters that returns values.
@Query("SELECT * from word_table ORDER BY word ASC") la base de données Room pour l'ensemble de l'application. Faites
LiveData<List<Word>>getAllWords(); de votre RoomDatabase un singleton pour éviter d'avoir plusieurs
instances de la base de données ouvertes en même temps, ce qui
// Query with parameter that returns a specific word or words. serait une mauvaise pratique.
@Query("SELECT * FROM word_table WHERE word LIKE :word ")
public LiveData<List<Word>> findWord(String word);
}
17 18
18/02/2021 18/02/2021
@Database(entities = {Word.class}, version = 1)
public abstract class WordRoomDatabase extends RoomDatabase {
public abstract WordDao wordDao();
private static WordRoomDatabase INSTANCE; public class WordRepository {
static WordRoomDatabase getDatabase(final Context context) { private WordDao mWordDao;
if (INSTANCE == null) { private LiveData<List<Word>> mAllWords;
synchronized (WordRoomDatabase.class) {
if (INSTANCE == null) { WordRepository(Application application) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), WordRoomDatabase db = WordRoomDatabase.getDatabase(application);
WordRoomDatabase.class, "word_database") mWordDao = db.wordDao();
// Wipes and rebuilds instead of migrating mAllWords = mWordDao.getAllWords();
// if no Migration object. }
.fallbackToDestructiveMigration()
.build(); LiveData<List<Word>> getAllWords() {
} return mAllWords;
}} }
return INSTANCE;
}} public void insert (Word word) {
new insertAsyncTask(mWordDao).execute(word);
}
private static class insertAsyncTask extends AsyncTask<Word, Void, Void> {
Repository ViewModel
Un repository est une classe qui résume l'accès à plusieurs LeViewModel est une classe dont le rôle est de fournir des
sources de données. données à l'interface utilisateur et de survivre aux
constitue une meilleure pratique pour la séparation de code changements de configuration.
et l'architecture. UnViewModel agit comme un centre de communication
Un repository est l'endroit où vous mettriez le code pour gérer entre le repository et l'interface utilisateur
les threads de requête et utiliser plusieurs backends.
par exemple : décider de récupérer les données d'un réseau
(service web) ou d'utiliser les résultats mis en cache dans la
base de données.
19 20
18/02/2021
Voici le code complet d'un exemple deViewModel :
public class WordViewModel extends AndroidViewModel {
private WordRepository mRepository;
private LiveData<List<Word>> mAllWords;
public WordViewModel (Application application) {
super(application);
mRepository = new WordRepository(application);
mAllWords = mRepository.getAllWords();
}
LiveData<List<Word>> getAllWords() { return mAllWords; }
public void insert(Word word) { mRepository.insert(word); }
}
21