Salvare i dati in un database locale utilizzando Room Parte di Android Jetpack.
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.
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'
@Databaseannotazione che include unentitiesarray 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: