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.
  • Uproszczone ścieżki migracji baz danych.

Z tych powodów zdecydowanie zalecamy korzystanie z biblioteki Room zamiast bezpośredniego używania interfejsów API SQLite.

Konfiguracja

Aby używać Room w aplikacji, dodaj te zależności do pliku build.gradle aplikacji.

Kotlin

dependencies {
    val room_version = "2.8.2"

    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.8.2"

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

Główne komponenty

Room ma 3 główne komponenty:

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.

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

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 metody, których pozostała część aplikacji używa do interakcji z danymi w tabeli 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);
}

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 klasę RoomDatabase.
  • Dla każdej klasy DAO powiązanej z bazą danych klasa bazy danych musi zdefiniować metodę abstrakcyjną, która nie ma argumentów i zwraca instancję klasy 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();
}

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

Jeśli aplikacja działa w wielu procesach, w wywołaniu narzędzia do tworzenia bazy danych umieść enableMultiInstanceInvalidation(). 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:

Kotlin

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

Java

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

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

Kotlin

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

Java

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

Dodatkowe materiały

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

Próbki

Codelabs

Blogi