Salvare i dati in un database locale utilizzando Room   Parte di Android Jetpack.

Prova con la multipiattaforma Kotlin
La multipiattaforma Kotlin consente di condividere il livello del database con altre piattaforme. Scopri come configurare e utilizzare il database Room in KMP

Le app che gestiscono quantità non banali di dati strutturati possono trarre notevoli vantaggi dalla persistenza di questi dati in locale. Il caso d'uso più comune è la memorizzazione nella cache di parti di dati pertinenti, in modo che quando il dispositivo non può accedere alla rete, gli utenti possano comunque sfogliare i contenuti offline.

La libreria di persistenza Room fornisce un livello di astrazione su SQLite per consentire un accesso fluido al database sfruttando tutta la potenza di SQLite. In particolare, Room offre i seguenti vantaggi:

  • Verifica in fase di compilazione delle query SQL.
  • Annotazioni pratiche che riducono al minimo il codice boilerplate ripetitivo e soggetto a errori.
  • Percorsi di migrazione del database semplificati.

Ti consigliamo di utilizzare Room anziché utilizzare le API SQLite direttamente.

Configurazione

Per utilizzare Room nella tua app, aggiungi le seguenti dipendenze al file build.gradle.kts del modulo. Room 3.0 richiede KSP per l'elaborazione delle annotazioni.

Kotlin

dependencies {
    val room_version = "3.0.0"

    implementation("androidx.room3:room3-runtime:$room_version")
    ksp("androidx.room3:room3-compiler:$room_version")
}

Groovy

dependencies {
    def room_version = "3.0.0"

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

    ksp "androidx.room3:room3-compiler:$room_version"
}

Componenti principali

Room ha tre componenti principali:

  • La classe del database che contiene il database e funge da punto di accesso principale per la connessione sottostante ai dati persistenti dell'app.
  • Le entità di dati che rappresentano le tabelle nel database dell'app.
  • Gli oggetti di accesso ai dati (DAO) che forniscono funzioni che l'app può utilizzare per eseguire query, aggiornare, inserire ed eliminare dati nel database.

La classe del database fornisce all'app le istanze dei DAO associati a quel database. A sua volta, l'app può utilizzare i DAO per recuperare i dati dal database come istanze degli oggetti di entità di dati associati. L'app può anche utilizzare le entità di dati definite per aggiornare le righe delle tabelle corrispondenti o per creare nuove righe da inserire. La Figura 1 illustra la relazione tra i diversi componenti di Room.

Figura 1. Diagramma dell'architettura della libreria Room.

Esempio di implementazione

Questa sezione presenta un esempio di implementazione di un database Room con una singola entità di dati e un singolo DAO.

Entità di dati

Il codice seguente definisce un'entità di dati User. Ogni istanza di User rappresenta una riga in una tabella user nel database dell'app.

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

Per saperne di più sulle entità di dati in Room, consulta Definire i dati utilizzando le entità Room.

Oggetto di accesso ai dati (DAO)

Il codice seguente definisce un DAO denominato UserDao. UserDao fornisce le funzioni che il resto dell'app utilizza per interagire con i dati nella tabella user.

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

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

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

    @Insert
    suspend fun insertAll(vararg users: User)

    @Delete
    suspend fun delete(user: User)
}

Per saperne di più sui DAO, consulta Accedere ai dati utilizzando i DAO Room.

Database

Il codice seguente definisce una classe AppDatabase per contenere il database. AppDatabase definisce la configurazione del database e funge da punto di accesso principale dell'app ai dati persistenti. La classe del database deve soddisfare le seguenti condizioni:

  • La classe deve essere annotata con un' @Database annotazione che include un entities array che elenca tutte le entità di dati associate al database.
  • La classe deve essere una classe astratta che estende RoomDatabase.
  • Per ogni classe DAO associata al database, la classe del database deve definire una funzione astratta che non accetta argomenti e restituisce un'istanza della classe DAO.

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

Nota: se la tua app viene eseguita in un singolo processo, devi seguire il pattern di progettazione singleton quando crei un'istanza di un AppDatabase oggetto. Ogni istanza di RoomDatabase è piuttosto costosa e raramente è necessario accedere a più istanze all'interno di un singolo processo.

Se la tua app viene eseguita in più processi, includi enableMultiInstanceInvalidation() nella chiamata al builder del database. In questo modo, quando hai un'istanza di AppDatabase in ogni processo, puoi invalidare il file di database condiviso in un processo, e questa invalidazione si propaga automaticamente alle istanze di AppDatabase all'interno di altri processi.

Utilizzo

Dopo aver definito l'entità di dati, il DAO e l'oggetto del database, puoi utilizzare il seguente codice per creare un'istanza del database:

val db =
    Room.databaseBuilder<AppDatabase>(applicationContext, "database-name")
        .setDriver(AndroidSQLiteDriver())
        .build()

Puoi quindi utilizzare le funzioni astratte di AppDatabase per ottenere un'istanza del DAO. A sua volta, puoi utilizzare le funzioni dell'istanza DAO per interagire con il database:

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

Risorse aggiuntive

Per saperne di più su Room, consulta le seguenti risorse aggiuntive:

Esempi