English English

Room Database - Sauvegardez les données de l'application dans un format de base de données plus facilement

Room est une bibliothèque de persistance qui fournit une couche abstraite via SQLite. Ceci permet un accès facile et sécurisé sans avoir à renoncer à la fonction SQLite. Dans ce tutoriel, vous apprendrez comment créer une base de données et comment interroger et modifier les données de la base de données.

Pourquoi utiliser Room et pas seulement SQLite directement ?

Avec Room vous avez la vérification du code SQL pendant la compilation. Ceci n'est pas disponible avec SQLite. En outre, si vous modifiez le schéma de base de données, toutes les requêtes SQL affectées doivent également être modifiées et ajustées manuellement.
Room est une bibliothèque de mappage relationnel d'objets qui relie les objets Java aux objets de la base de données, rendant l'accès beaucoup plus rapide et facile. Les principaux composants de Room sont par exemple "Entities", "DAO", etc., que l'on trouve également dans les programmes Java avec Hibernate. La documentation officielle de Room se trouve sur ce site web : https://developer.android.com/topic/libraries/architecture/room.html

Pour ce tutoriel, vous avez besoin d'Android Studio avec un SDK installé (depuis Android 5). Il est programmé avec Java. La base de données et les méthodes nécessaires sont créées pour stocker les données d'une application de gamme.

Mise en place des conditions préalables

De nouvelles dépendances sont nécessaires pour configurer la base de données. Room et RxJava2 doivent maintenant être installés. Ajoutez ceci à la section "dependencies" dans le fichier gradle de l'application (le fichier "build.gradle (Module : app)" - situé sous la section Gradle Scripts) dans le projet nouvellement créé. La dernière version de Room est disponible sur ce site web : https://developer.android.com/jetpack/androidx/releases/room
La dernière version de RxJava : https://github.com/ReactiveX/RxJava/tree/2.x

Ces dépendances sont obligatoires. Ce tutoriel utilise la version "Room" 2.1.0-rc01, "RxJava" 2.1.0 et "RxAndroid" 2.0.1 :

implementation 'android.arch.persistence.room:runtime:2.1.0-rc01'
implementation 'android.arch.persistence.room:rxjava2:2.1.0-rc01'
annotationProcessor 'android.arch.persistence.room:compiler:2.1.0-rc01'
implementation 'io.reactivex.rxjava2:rxjava:2.1.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'


Veuillez lancer la synchronisation Gradle pour télécharger les nouvelles dépendances.

Datenmodell erstellen

Les tables de la base de données sont maintenant créées. Un nouveau "modèle" de package est créé et les tables y sont sauvegardées.
Une table correspond à une classe Java et à une entité, qui contient des annotations. La classe Java est "publique".

C'est ici que la classe Java "Task" est créée, qui stocke les tâches.

@Entity(tableName = "task")
public class Task {

    @NonNull
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name="id")
    private int id;

    @NonNull
    @ColumnInfo(name="taskname")
    private String taskName;

    @ColumnInfo(name="duedate")
    private Date dueDate;

    @ColumnInfo(name="priority")
    private int priority;


    public Task(){

    }

    @Ignore
    public Task(int id, @NonNull String taskName, Date dueDate, String category, int priority, int points) {
        this.id = id;
        this.taskName = taskName;
        this.dueDate = dueDate;
        this.priority = priority;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @NonNull
    public String getTaskName() {
        return taskName;
    }

    public void setTaskName(@NonNull String taskName) {
        this.taskName = taskName;
    }

    public Date getDueDate() {
        return dueDate;
    }

    public void setDueDate(Date dueDate) {
        this.dueDate = dueDate;
    }


    public int getPriority() {
        return priority;
    }

    public void setPriority(int priority) {
        this.priority = priority;
    }

Les colonnes de la table sont définies à l'aide de variables d'instance. Les colonnes "id", "taskname", "duedate" et "priority" sont créées ici.
Important : Les méthodes Get....() et set....() sont nécessaires pour toutes les variables d'instance.
Un constructeur vide ( ici Task()) doit également être créé. D'autres constructeurs peuvent également être ajoutés. Ici, un deuxième constructeur a été créé, qui n'est utilisé que par nous et non par la "room library".


@Entity: Définissez cette classe Java comme une table. Avec tableName, un nom de la table est défini, qui peut également différer du nom de la classe Java.

@ColumnInfo: Ajoutez un nom pour les colonnes. Peut aussi avoir un nom complètement différent de celui de la variable d'instance.

@PrimaryKey: Définissez la clé primaire de la base de données. autoGenerate crée automatiquement une clé primaire pour l'enregistrement.

@NonNull: Quand une colonne a besoin d'une valeur ajoutée. N'oubliez pas de l'ajouter à la clé primaire.

@Ignore: Le code marqué avec cette annotation est ignoré par Room, puis n'est pas traité. Ceci est utile, par exemple, si un objet ne doit pas être enregistré dans la base de données.

Optionnellement, une méthode toString() peut être ajoutée à cette classe. Ceci vous permet d'éditer les variables d'instance de la classe lorsque vous appelez directement l'objet de classe.

Créer une "interface DAO"

Vous devez maintenant créer une classe Java de type "Interface". La classe doit porter l'annotation "@Dao". Les fonctionnalités qui peuvent être implémentées ultérieurement (mise à jour, ajout ou suppression de données) sont créées comme méthodes d'interface dans cette interface DAO. En outre, les méthodes de récupération des données dans la base de données sont définies ici.

@Dao
public interface AppDAO {

    @Query("Select * from task where id=:id")
    Flowable<Task> getTaskById(int id);

    @Query("Select * from task")
    Flowable<List<Task>> getAllTasks();

    @Insert
    void insertTask(Task... tasks);

    @Update
    void updateTask(Task... tasks);

    @Delete
    void deleteTask(Task task);

    @Query("Delete from task")
    void deleteAllTasks();

}

Above the interface method, annotations are used to define how to access the database.
@Dao - Define class as DAO interface.
@Insert - This method will add records. This means a query of type "Insert" will be executed.
@Update - This method will update records.
@Delete - This method to delete a record
@Query - Define the database operations to be performed directly using SQL commands.

 

Créer une base de données

Créez maintenant une classe abstraite ("public abstract class") qui doit hériter de la classe RoomDatabase ("extends", classe existante de Room). Cette classe abstraite crée la base de données de cette application.

@Database(version = 1, entities = {Task.class})
public abstract class AppDatabase extends RoomDatabase {

    //Nom de la base de données à créer
    public static final String DATABASE_NAME ="Tasks-App-Database";

    public abstract AppDAO appDAO();

    //L'instance de la base de données
    private static AppDatabase dbInstance;

    public static AppDatabase getInstance(Context context){
        if (dbInstance == null){
            dbInstance = Room.databaseBuilder(context,AppDatabase.class,DATABASE_NAME).
                    fallbackToDestructiveMigration().
                    build();
        }
        return dbInstance;
    }
}

La classe doit avoir une annotation @Database et dans cette annotation les classes d'entités correspondant à une table sont ajoutées. Bien sûr, plusieurs classes d'entités peuvent être ajoutées directement, mais elles sont séparées par des virgules.
fallbackToDestructiveMigration() - Cette fonction permet de recréer la base de données lorsqu'un nouveau schéma est créé.


 

Créer des fonctions (méthodes) pour la base de données

Les méthodes créées dans l'interface DAO sont maintenant implémentées. Avec ces méthodes, il est possible d'accéder à la base de données via le code Java. Maintenant, une interface et deux classes seront créées pour implémenter cette interface (" Implements).

1. Une classe d'interface doit être créée avec les variables et les méthodes d'interface de la classe d'interface DAO AppDAO.

public interface AppDataSourceInterface {
    Flowable<Task> getTaskById(int id);
    Flowable<List<Task>> getAllTasks();
    void insertTask(Task... tasks);
    void updateTask(Task... tasks);
    void deleteTask(Task task);
    void deleteAllTasks();
}



2. Maintenant une classe est créée qui implémente les méthodes de la classe d'interface précédemment créée.

public class AppDataSource implements AppDataSourceInterface {

    private AppDAO appDAO;
    private static AppDataSource dbInstance;


    @Override
    public Flowable<Task> getTaskById(int id) {
        return appDAO.getTaskById(id);
    }

    @Override
    public Flowable<List<Task>> getAllTasks() {
        return appDAO.getAllTasks();
    }

    @Override
    public void insertTask(Task... tasks) {
        appDAO.insertTask(tasks);
    }

    @Override
    public void updateTask(Task... tasks) {
        appDAO.updateTask(tasks);
    }

    @Override
    public void deleteTask(Task task) {
        appDAO.deleteTask(task);
    }

    @Override
    public void deleteAllTasks() {
        appDAO.deleteAllTasks();
    }
}

Dans les méthodes implémentées, les méthodes correspondantes sont appelées par l'interface DAO appDAO.  


3. Maintenant une classe est créée qui est utilisée comme référentiel. Cette classe nouvellement créée implémente également l'interface

public class AppRepository implements AppDataSourceInterface {

    private AppDataSourceInterface dbLocalDataSource;

    private static AppRepository dbInstance;

    public AppRepository(AppDataSourceInterface dbLocalDataSource){
        this.dbLocalDataSource = dbLocalDataSource
    }


    public static AppRepository getInstance(AppDataSourceInterface dbLocalDataSource){
        if (dbInstance == null){
            dbInstance = new AppRepository(dbLocalDataSource);
        }
        return dbInstance;
    }

    @Override
    public Flowable<Task> getTaskById(int id) {
        return dbLocalDataSource.getTaskById(id);
    }

    @Override
    public Flowable<List<Task>> getAllTasks() {
        return dbLocalDataSource.getAllTasks();
    }

    @Override
    public void insertTask(Task... tasks) {
         dbLocalDataSource.insertTask(tasks);
    }

    @Override
    public void updateTask(Task... tasks) {
         dbLocalDataSource.updateTask(tasks);
    }

    @Override
    public void deleteTask(Task task) {
        dbLocalDataSource.deleteTask(task);
    }

    @Override
    public void deleteAllTasks() {
        dbLocalDataSource.deleteAllTasks();
    }
} 

Cette classe est ensuite utilisée pour traiter les données de la base de données à l'aide du code Java (par exemple, dans la classe MainActivity.java).

 

Modification des données dans la base de données

Les méthodes précédemment créées peuvent maintenant être utilisées, par exemple, pour ajouter, modifier, etc. des données.

Dans MainActivity.Java, une liste et un ArrayAdapter seront créés. La liste se compose d'objets de classe de la classe "Task" et stocke toutes les tâches dans une "Array List". Ces objets Java sont utilisés pour interroger et éditer la base de données.

List<Task> taskList;
ArrayAdapter adapter;

private CompositeDisposable compositeDisposable;
private AppRepository appRepository;

Les données sont chargées à partir de la base de données à l'aide d'un objet de type Jetable. Un jetable envoie des données qui sont ensuite traitées par les abonnés. Un objet jetable se compose d'un ou plusieurs abonnés. "Disposable" est également utilisé pour toutes les autres activités (ajout de données à la base de données, suppression de données de la base de données, ....) sur la base de données.

Pour récupérer les données de la base de données, une classe interne anonyme doit être créée pour l'interface Consumer.

Disposable disposable = appRepository.getAllTasks()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<List<Task>>() {
                    @Override
                    public void accept(List<Task> tasks) throws Exception {
                        onGetAllTaskSucess(tasks);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                    //Voici les fonctions qui doivent être exécutées lorsque la base de données a été appelée avec succès. Peut aussi être vide ou n'afficher qu'un message dans un "toast".
                    }
                });
        compositeDisposable.add(disposable);

Dans l'interface "Consumer" la méthode accept() (qui se trouve dans une classe anonyme interne) est écrasée. La méthode accept() obtient en argument (List<Task> tasks) la table "Task", qui a été convertie de la base de données en liste.

Dans la méthode onGetAllTaskSucess(tasks) de la classe principale MainActivity.java tous les enregistrements sont chargés depuis la base de données et stockés dans une liste.

private void onGetAllTaskSucess(List<Task> tasks) {
    taskList.clear();
    taskList.addAll(tasks);
    adapter.notifyDataSetChanged();
}


Les données sont ajoutées à la base de données (une nouvelle tâche - nouvel enregistrement dans la table Task) également via un objet jetable. Pour éditer les données de la base de données, une classe interne anonyme doit être créée pour l'interface ObservableOnSubscribe.

addButton = (FloatingActionButton) findViewById(R.id.addTaskButon);
addButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Disposable disposable = io.reactivex.Observable.create(new ObservableOnSubscribe<Object>(

                ) {
                    @Override
                    public void subscribe(ObservableEmitter<Object> emitter) throws Exception {
                        //Commands to save or delete data in the database
                        Task task = new Task();
                        task.setTaskName(textfield1.getText());
                        appRepository.insertTask(task);
                    }
                })
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribeOn(Schedulers.io())
                        .subscribe(new Consumer() {
                                       @Override
                                       public void accept(Object o) throws Exception {
                                            //Impression d'un message de confirmation
                                       }
                                   }, new Consumer<Throwable>() {
                                       @Override
                                       public void accept(Throwable throwable) throws Exception {
                                           //Affiche les messages d'erreur de la variable throwable
                                       }
                                   }, new Action() {
                                       @Override
                                       public void run() throws Exception {
                                           //Charger à nouveau les données de la base de données.
                                           loadDatabaseData();
                                       }
                                   }
                        );
            }
        }); 

Lorsqu'on clique sur le bouton ajouter, le texte saisi par l'utilisateur dans le champ texte "textfield1" est enregistré dans la base de données dans la colonne "nom de la tâche". L'interface "ObservableOnSubscribe" permet de modifier les données de la base de données. Dans cette interface, la seule méthode "subscribe()" est écrasée par les commandes de la base de données à exécuter. Enfin, la méthode subscribe() est appelée, où vous programmez ce qui doit se passer après l'édition des données de la base de données.
        
        
Les données de la base de données peuvent ensuite être traitées avec ces commandes dans une activité (ici : MainActivity.java). La meilleure façon d'afficher les données de la base de données est une ListView, qui affiche ensuite toutes les valeurs d'un enregistrement de base de données dans une liste.

Catégorie :

We use cookies on our website. Some of them are essential for the operation of the site, while others help us to improve this site and the user experience (tracking cookies). You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.

Ok