Zapisywanie danych w lokalnej bazie danych za pomocą biblioteki Room, części Androida Jetpack.

Wypróbuj Kotlin Multiplatform
Kotlin Multiplatform (KMP) umożliwia udostępnianie warstwy bazy danych innym platformom. Dowiedz się, jak skonfigurować bazę danych Room i z niej korzystać w KMP

Aplikacje, które przetwarzają duże ilości uporządkowanych danych, mogą korzystać z lokalnego przechowywania tych danych. Najczęstszym zastosowaniem jest przechowywanie w pamięci podręcznej odpowiednich fragmentów danych, aby użytkownik mógł przeglądać treści w trybie offline, gdy urządzenie nie ma dostępu do sieci.

Biblioteka trwałości danych Room zapewnia warstwę abstrakcji nad SQLite, aby umożliwić płynny dostęp do bazy danych przy jednoczesnym wykorzystaniu pełnej mocy SQLite. W szczególności Room zapewnia te korzyści:

  • Weryfikacja zapytań SQL w czasie kompilowania.
  • Adnotacje ułatwiające pracę, które minimalizują podatny na błędy powtarzalny kod.
  • Usprawnione ścieżki migracji bazy danych.

Zamiast bezpośrednio korzystać z interfejsów API SQLite, zalecamy używanie biblioteki Room.

Konfiguracja

Aby używać biblioteki Room w aplikacji, dodaj te zależności do pliku build.gradle.kts modułu. Room 3.0 wymaga KSP do przetwarzania adnotacji.

Kotlin

dependencies {
    val room_version = "3.0.0"

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

Dynamiczny

dependencies {
    def room_version = "3.0.0"

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

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

Główne komponenty

Room składa się z 3 głównych komponentów:

Klasa bazy danych udostępnia aplikacji instancje obiektów DAO powiązanych z tą bazą danych. Aplikacja może z kolei używać obiektów DAO do pobierania danych z bazy danych jako instancji powiązanych obiektów encji danych. Aplikacja może też używać zdefiniowanych jednostek danych do aktualizowania wierszy w odpowiednich tabelach lub tworzenia nowych wierszy do wstawienia. Rysunek 1 przedstawia relacje między poszczególnymi komponentami Room.

Rysunek 1. Schemat architektury biblioteki Room.

Przykładowa implementacja

W tej sekcji znajdziesz przykładową implementację bazy danych Room z jedną encją danych i jednym obiektem DAO.

Encja danych

Poniższy kod definiuje encję danych User. Każda instancja User reprezentuje wiersz w tabeli user w bazie danych aplikacji.

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

Więcej informacji o encjach danych w bibliotece Room znajdziesz w artykule Definiowanie danych za pomocą encji Room.

Obiekt umożliwiający dostęp do danych (DAO)

Poniższy kod definiuje obiekt DAO o nazwie UserDao. UserDao udostępnia funkcje, których reszta aplikacji używa do interakcji z danymi w tabeli 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)
}

Więcej informacji o obiektach DAO znajdziesz w artykule Uzyskiwanie dostępu do danych za pomocą obiektów DAO w bibliotece Room.

Baza danych

Poniższy kod definiuje klasę AppDatabase, która będzie przechowywać bazę danych. AppDatabase definiuje konfigurację bazy danych i służy jako główny punkt dostępu aplikacji do utrwalonych danych. Klasa bazy danych musi spełniać te warunki:

  • Klasa musi być oznaczona jako @Database, która zawiera tablicę entities z listą wszystkich encji danych powiązanych z bazą danych.
  • Klasa musi być klasą abstrakcyjną, która rozszerza RoomDatabase.
  • W przypadku każdej klasy DAO powiązanej z bazą danych klasa bazy danych musi definiować funkcję abstrakcyjną, która nie przyjmuje argumentów i zwraca instancję klasy DAO.

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

Uwaga: jeśli aplikacja działa w jednym procesie, podczas tworzenia instancji obiektu AppDatabase należy stosować wzorzec projektowy singleton. Każda instancja RoomDatabase jest dość kosztowna i rzadko potrzebujesz dostępu do wielu instancji w jednym procesie.

Jeśli aplikacja działa w wielu procesach, dodaj enableMultiInstanceInvalidation() do wywołania narzędzia do tworzenia bazy danych. Dzięki temu, gdy w każdym procesie masz instancję AppDatabase, możesz unieważnić udostępniony plik bazy danych w jednym procesie, a to unieważnienie automatycznie rozprzestrzeni się na instancje AppDatabase w innych procesach.

Wykorzystanie

Po zdefiniowaniu encji danych, obiektu DAO i obiektu bazy danych możesz użyć tego kodu, aby utworzyć instancję bazy danych:

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

Następnie możesz użyć funkcji abstrakcyjnych z AppDatabase, aby uzyskać instancję DAO. Z kolei funkcji z instancji DAO możesz używać do interakcji z bazą danych:

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

Dodatkowe materiały

Więcej informacji o bibliotece Room znajdziesz w tych materiałach:

Przykłady