Salva i dati in un database locale utilizzando Room Componente di Android Jetpack.

Le app che gestiscono quantità non banali di dati strutturati possono trarre grande vantaggio dalla persistenza di questi dati localmente. Il caso d'uso più comune è memorizzare nella cache i dati rilevanti in modo che, quando il dispositivo non può accedere alla rete, l'utente possa comunque sfogliare i contenuti mentre è offline.

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

  • Verifica in fase di compilazione delle query SQL.
  • Annotazioni utili che riducono al minimo i codici boilerplate ripetitivi e soggetti a errori.
  • Percorsi di migrazione dei database semplificati.

Per questo motivo, ti consigliamo vivamente di utilizzare Room invece di direttamente le API SQLite.

Configurazione

Per utilizzare Room nella tua app, aggiungi le seguenti dipendenze al file build.gradle dell'app:

Trendy

dependencies {
    def room_version = "2.6.1"

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

    // To use Kotlin annotation processing tool (kapt)
    kapt "androidx.room:room-compiler:$room_version"
    // To use Kotlin Symbol Processing (KSP)
    ksp "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"
}

Kotlin

dependencies {
    val room_version = "2.6.1"

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

    // To use Kotlin annotation processing tool (kapt)
    kapt("androidx.room:room-compiler:$room_version")
    // To use Kotlin Symbol Processing (KSP)
    ksp("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")
}

Componenti principali

Nella stanza virtuale sono presenti tre componenti principali:

  • La classe di database che contiene il database e funge da punto di accesso principale per la connessione sottostante ai dati persistenti della tua app.
  • Entità di dati che rappresentano tabelle nel database dell'app.
  • Oggetti di accesso ai dati (DAO) che forniscono metodi che l'app può utilizzare per eseguire query, aggiornare, inserire ed eliminare dati nel database.

La classe di database fornisce alla tua app le istanze degli DAO associati al database. A sua volta, l'app può utilizzare i DAO per recuperare i dati dal database sotto forma di istanze degli oggetti dell'entità dati associati. L'app può anche utilizzare le entità di dati definite per aggiornare le righe delle tabelle corrispondenti o creare nuove righe per l'inserimento. La Figura 1 illustra la relazione tra i diversi componenti della camera.

Figura 1. Diagramma dell'architettura della biblioteca di una stanza.

Implementazione di esempio

Questa sezione presenta un esempio di implementazione di un database di camere con una singola entità 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.

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;
}

Per scoprire di più sulle entità di dati in una camera, consulta Definizione dei dati utilizzando le entità di una camera.

Oggetto di accesso ai dati (DAO)

Il codice seguente definisce un DAO denominato UserDao. UserDao fornisce i metodi utilizzati dal resto dell'app per interagire con i dati nella tabella 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);
}

Per scoprire di più sugli DAO, vedi Accedere ai dati utilizzando i DAO in camera.

Database

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

  • La classe deve essere annotata con un'annotazione @Database che include un array entities che elenca tutte le entità di dati associate al database.
  • La classe deve essere una classe astratta che si estende RoomDatabase.
  • Per ogni classe DAO associata al database, la classe di database deve definire un metodo astratto con zero argomenti e che restituisca un'istanza della 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();
}

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

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

Utilizzo

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

Kotlin

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

Java

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

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

Kotlin

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

Java

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

Risorse aggiuntive

Per scoprire di più sulla stanza, consulta le seguenti risorse aggiuntive:

Samples

Codelab

Blog