Enregistrer des données dans une base de données locale à l'aide de Room   Fait partie d'Android Jetpack.

La persistance de données structurées en local peut s'avérer particulièrement bénéfique pour les applications qui gèrent ces données en très grandes quantités. Le cas d'utilisation le plus courant consiste à mettre en cache les éléments de données pertinents de sorte que, lorsque l'appareil ne peut pas accéder au réseau, l'utilisateur puisse continuer à parcourir ce contenu hors connexion.

La bibliothèque de persistance Room fournit une couche d'abstraction sur SQLite afin de permettre un accès fluide à la base de données, tout en exploitant toute la puissance de SQLite. Room offre, en particulier, les avantages suivants :

  • Une vérification des requêtes SQL au moment de la compilation.
  • Des annotations pratiques qui réduisent le code récurrent qui peut s'avérer répétitif et être sujet aux erreurs.
  • Des chemins de migration simplifiés pour les bases de données.

Compte tenu de ces éléments, il est vivement conseillé d'utiliser Room plutôt que d'utiliser directement les API SQLite.

Configuration

Pour utiliser Room dans votre application, ajoutez les dépendances suivantes à son fichier build.gradle.

Kotlin

dependencies {
    val room_version = "2.6.1"

    implementation("androidx.room:room-runtime:$room_version")

    // If this project uses any Kotlin source, use Kotlin Symbol Processing (KSP)
    // See Add the KSP plugin to your project
    ksp("androidx.room:room-compiler:$room_version")

    // If this project only uses Java source, use the Java annotationProcessor
    // No additional plugins are necessary
    annotationProcessor("androidx.room:room-compiler:$room_version")

    // optional - Kotlin Extensions and Coroutines support for Room
    implementation("androidx.room:room-ktx:$room_version")

    // optional - RxJava2 support for Room
    implementation("androidx.room:room-rxjava2:$room_version")

    // optional - RxJava3 support for Room
    implementation("androidx.room:room-rxjava3:$room_version")

    // optional - Guava support for Room, including Optional and ListenableFuture
    implementation("androidx.room:room-guava:$room_version")

    // optional - Test helpers
    testImplementation("androidx.room:room-testing:$room_version")

    // optional - Paging 3 Integration
    implementation("androidx.room:room-paging:$room_version")
}

Groovy

dependencies {
    def room_version = "2.6.1"

    implementation "androidx.room:room-runtime:$room_version"

    // If this project uses any Kotlin source, use Kotlin Symbol Processing (KSP)
    // See KSP Quickstart to add KSP to your build
    ksp "androidx.room:room-compiler:$room_version"

    // If this project only uses Java source, use the Java annotationProcessor
    // No additional plugins are necessary
    annotationProcessor "androidx.room:room-compiler:$room_version"

    // optional - RxJava2 support for Room
    implementation "androidx.room:room-rxjava2:$room_version"

    // optional - RxJava3 support for Room
    implementation "androidx.room:room-rxjava3:$room_version"

    // optional - Guava support for Room, including Optional and ListenableFuture
    implementation "androidx.room:room-guava:$room_version"

    // optional - Test helpers
    testImplementation "androidx.room:room-testing:$room_version"

    // optional - Paging 3 Integration
    implementation "androidx.room:room-paging:$room_version"
}

Composants principaux

Room repose sur trois composants principaux :

  • La classe de base de données qui contient la base de données et sert de point d'accès principal pour la connexion sous-jacente aux données persistantes de votre application.
  • Les entités de données qui représentent les tables de la base de données de votre application.
  • Les objets d'accès aux données (DAO) qui fournissent des méthodes que votre application peut utiliser pour interroger, mettre à jour, insérer et supprimer des données dans la base de données

La classe de base de données fournit à votre application des instances des DAO associés à cette base de données. L'application peut ensuite utiliser ces DAO pour récupérer des données de la base de données en tant qu'instances des objets d'entité associés. L'application peut également utiliser les entités de données définies pour mettre à jour des lignes dans les tables correspondantes ou pour créer des lignes à insérer. La figure 1 illustre la relation entre les différents composants de Room.

Figure 1. Schéma de l'architecture de la bibliothèque Room.

Exemple d'implémentation

Cette section présente un exemple d'implémentation d'une base de données Room avec une seule entité de données et un seul DAO.

Entité de données

Le code suivant définit une entité de données User. Chaque instance de User représente une ligne dans une table user de la base de données de l'application.

Kotlin

@Entity
data class User(
    @PrimaryKey val uid: Int,
    @ColumnInfo(name = "first_name") val firstName: String?,
    @ColumnInfo(name = "last_name") val lastName: String?
)

Java

@Entity
public class User {
    @PrimaryKey
    public int uid;

    @ColumnInfo(name = "first_name")
    public String firstName;

    @ColumnInfo(name = "last_name")
    public String lastName;
}

Pour en savoir plus sur les entités de données dans Room, consultez Définir des données à l'aide d'entités Room.

Objet d'accès aux données (DAO)

Le code suivant définit un DAO appelé UserDao. UserDao fournit les méthodes utilisées par le reste de l'application pour interagir avec les données de la table user.

Kotlin

@Dao
interface UserDao {
    @Query("SELECT * FROM user")
    fun getAll(): List<User>

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    fun loadAllByIds(userIds: IntArray): List<User>

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
           "last_name LIKE :last LIMIT 1")
    fun findByName(first: String, last: String): User

    @Insert
    fun insertAll(vararg users: User)

    @Delete
    fun delete(user: User)
}

Java

@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    List<User> getAll();

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    List<User> loadAllByIds(int[] userIds);

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
           "last_name LIKE :last LIMIT 1")
    User findByName(String first, String last);

    @Insert
    void insertAll(User... users);

    @Delete
    void delete(User user);
}

Pour en savoir plus sur les DAO, consultez Accéder aux données avec les DAO de Room.

Base de données

Le code suivant définit une classe AppDatabase destinée à contenir la base de données. AppDatabase définit la configuration de la base de données et sert de point d'accès principal de l'application aux données persistantes. La classe de base de données doit remplir les conditions suivantes :

  • La classe doit comporter une annotation @Database qui inclut un tableau entities listant toutes les entités de données associées à la base de données.
  • La classe doit être une classe abstraite qui étend RoomDatabase.
  • Pour chaque classe DAO associée à la base de données, la classe de base de données doit définir une méthode abstraite qui ne comporte aucun argument et qui renvoie une instance de la classe DAO.

Kotlin

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

Java

@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}

Remarque : Si votre application s'exécute dans un seul processus, vous devez suivre le patron de conception Singleton lors de l'instanciation d'un objet AppDatabase. Chaque instance RoomDatabase est assez coûteuse en ressources, et vous aurez rarement besoin d'accéder à plusieurs instances au cours d'un même processus.

Si votre application s'exécute dans plusieurs processus, incluez enableMultiInstanceInvalidation() dans votre appel du compilateur de base de données. Ainsi, lorsque vous aurez une instance de AppDatabase dans chaque processus, vous pourrez invalider le fichier de base de données partagé dans un processus et cette invalidation sera automatiquement propagée aux instances de AppDatabase dans les autres processus.

Utilisation

Après avoir défini l'entité de données, le DAO et l'objet de base de données, vous pouvez utiliser le code suivant pour créer une instance de la base de données :

Kotlin

val db = Room.databaseBuilder(
            applicationContext,
            AppDatabase::class.java, "database-name"
        ).build()

Java

AppDatabase db = Room.databaseBuilder(getApplicationContext(),
        AppDatabase.class, "database-name").build();

Vous pourrez ensuite utiliser les méthodes abstraites de la classe AppDatabase pour obtenir une instance du DAO. Par conséquent, vous pourrez utiliser les méthodes de l'instance DAO pour interagir avec la base de données :

Kotlin

val userDao = db.userDao()
val users: List<User> = userDao.getAll()

Java

UserDao userDao = db.userDao();
List<User> users = userDao.getAll();

Ressources supplémentaires

Pour en savoir plus sur Room, consultez les ressources supplémentaires suivantes :

Exemples

Ateliers de programmation

Blogs