Zapisywanie danych w lokalnej bazie danych za pomocą Room   Należy do Android Jetpack.

Aplikacje, które obsługują znaczne ilości uporządkowanych danych, mogą znacznie skorzystać z przechowywania tych danych lokalnie. Najczęstszym przypadkiem użycia jest przechowywanie w pamięci podręcznej odpowiednich części danych, aby w przypadku utraty dostępu do sieci użytkownik mógł nadal przeglądać te treści w trybie offline.

Biblioteka trwałości 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 oferuje te korzyści:

  • weryfikacja zapytań SQL w czasie kompilacji;
  • wygodne adnotacje, które minimalizują powtarzający się i podatny na błędy szablonowy kod;
  • Uproszczone ścieżki migracji bazy danych.

Z tego powodu zdecydowanie zalecamy korzystanie z Room zamiast bezpośredniego korzystania z interfejsów SQLite API.

Konfiguracja

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

KotlinGroovy
dependencies {
    val room_version = "2.6.1"

    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")
}
dependencies {
    def room_version = "2.6.1"

    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

Pokój składa się z 3 głównych elementów:

  • Klasa bazy danych, która przechowuje bazę danych i stanowi główne miejsce dostępu do połączenia z danymi zapisanymi w aplikacji.
  • Ewentycje danych reprezentujące tabele w bazie danych aplikacji.
  • obiekty dostępu do danych (DAO), które udostępniają metody, których aplikacja może używać do wysyłania zapytań, aktualizowania, wstawiania i usuwania danych w bazie danych;

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

Rysunek 1. Schemat architektury biblioteki Room

Przykładowa implementacja

W tej sekcji przedstawiono przykładową implementację bazy danych Room z jedną ością danych i jedną DAO.

Element danych

Poniższy kod definiuje element danych User. Każda instancja Userreprezentuje wiersz w tabeli user w bazie danych aplikacji.

KotlinJava
@Entity
data class User(
    @PrimaryKey val uid: Int,
    @ColumnInfo(name = "first_name") val firstName: String?,
    @ColumnInfo(name = "last_name") val lastName: String?
)
@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 podmiocie danych w Room znajdziesz w artykule Definiowanie danych za pomocą obiektów Room.

Obiekt dostępu do danych (DAO)

Poniższy kod definiuje DAO o nazwie UserDao. UserDao udostępnia metody, których reszta aplikacji używa do interakcji z danymi w tabeli user.

KotlinJava
@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)
}
@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 DAO znajdziesz w artykule Dostęp do danych za pomocą DAO Room.

Baza danych

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

  • Klasa musi być opatrzona adnotacją @Database, która zawiera tablicę entitiesz listą wszystkich elementów danych powiązanych z bazą danych.
  • Klasa musi być abstrakcyjną klasą rozszerzającą klasę RoomDatabase.
  • W przypadku 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.
KotlinJava
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}

Uwaga: jeśli aplikacja działa w ramach pojedynczego procesu, podczas tworzenia instancji obiektu AppDatabase należy przestrzegać wzorca projektowego singleton. Każda instancja RoomDatabase jest dość droga i rzadko potrzebujesz dostępu do wielu instancji w ramach jednego procesu.

Jeśli aplikacja działa w kilku procesach, podczas wywołania kreatora bazy danych dodaj enableMultiInstanceInvalidation(). Dzięki temu, jeśli masz wystąpienie AppDatabase w każdym procesie, możesz unieważnić plik współdzielonej bazy danych w jednym procesie, a unieważnienie zostanie automatycznie rozszerzone na wystąpienia AppDatabase w innych procesach.

Wykorzystanie

Po zdefiniowaniu encji danych, interfejsu DAO i obiektu bazy danych możesz użyć tego kodu do utworzenia instancji bazy danych:

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

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

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

Dodatkowe materiały

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

Próbki

Mir 2: Return of the King to wysokiej jakości gra mobilna o postaciach z Legendy, która została autoryzowana przez Actoz Soft i oparta na silniku Unity. Ta gra nie tylko doskonale odtwarza wrażenia z Mir 2, koreańskiej gry fantasy typu MMORPG, ale

Wuthering Waves to fabularna gra akcji z grafiką wysokiej jakości stworzona przez Kuro Games. Optymalizacja zużycia energii jest bardzo ważna, aby zapewnić użytkownikom najwyższą jakość wrażeń podczas długich sesji grania. Android Studio wprowadziło

Godot Engine to popularny wieloplatformowy silnik gier typu open source, który zapewnia solidne wsparcie dla Androida. Godot może służyć do tworzenia gier praktycznie dowolnego gatunku. Umożliwia tworzenie grafiki 2D i 3D. Wersja 4 Godota wprowadziła

Ćwiczenia z programowania

Blogi