Сохранение данных в локальной базе данных с помощью Room   Часть Android Jetpack.

Попробуйте Kotlin Multiplatform
Kotlin Multiplatform позволяет использовать уровень базы данных на разных платформах. Узнайте, как настроить базу данных Room в KMP и работать с ней.

Приложения, работающие со значительным объемом структурированных данных, могут получить большую выгоду от сохранения этих данных локально. Чаще всего кэшируются важные данные, чтобы пользователи могли просматривать контент, когда устройство не подключено к сети.

Библиотека персистентности Room предоставляет уровень абстракции над SQLite, обеспечивая удобный доступ к базе данных и позволяя использовать все возможности SQLite. В частности, Room предоставляет следующие преимущества:

  • Проверка SQL-запросов во время компиляции.
  • Удобные аннотации, которые минимизируют повторяющийся и подверженный ошибкам шаблонный код.
  • Оптимизированные пути миграции баз данных.

Мы рекомендуем использовать Room вместо прямого использования SQLite API.

Настроить

Чтобы использовать Room в приложении, добавьте в файл build.gradle.kts модуля следующие зависимости: Для обработки аннотаций в Room 3.0 требуется KSP.

Котлин

dependencies {
    val room_version = "3.0.3"

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

Классный

dependencies {
    def room_version = "3.0.3"

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

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

Основные компоненты

В Room есть три основных компонента:

  • Класс базы данных, который содержит базу данных и служит основной точкой доступа для базового подключения к сохраненным данным вашего приложения.
  • Сущности данных, которые представляют таблицы в базе данных приложения.
  • Объекты доступа к данным (DAO), которые предоставляют функции, позволяющие приложению запрашивать, обновлять, вставлять и удалять данные в базе данных.

Класс базы данных предоставляет вашему приложению экземпляры DAO, связанных с этой базой данных. В свою очередь, приложение может использовать DAO для извлечения данных из базы данных в виде экземпляров связанных объектов сущностей данных. Приложение также может использовать определенные сущности данных для обновления строк из соответствующих таблиц или для создания новых строк для вставки. На рисунке 1 показана взаимосвязь между различными компонентами Room.

Рисунок 1. Схема архитектуры библиотеки Room.

Пример реализации

В этом разделе представлен пример реализации базы данных Room с одной сущностью данных и одним DAO.

Сущность данных

В приведенном ниже коде определяется сущность данных User. Каждый экземпляр User представляет собой строку в таблице user в базе данных приложения.

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

Подробнее о сущностях данных в Room…

Объект доступа к данным (DAO)

В приведенном ниже коде определяется объект DAO под названием UserDao. UserDao предоставляет функции, которые остальная часть приложения использует для взаимодействия с данными в таблице 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)
}

Чтобы узнать больше о DAO, ознакомьтесь со статьей Доступ к данным с помощью Room DAO.

База данных

В следующем коде определяется класс AppDatabase для хранения базы данных. AppDatabase определяет конфигурацию базы данных и служит основной точкой доступа приложения к сохраненным данным. Класс базы данных должен соответствовать следующим условиям:

  • Класс должен быть аннотирован с помощью @Database, который включает массив entities со списком всех сущностей данных, связанных с базой данных.
  • Класс должен быть абстрактным и расширять RoomDatabase.
  • Для каждого класса DAO, связанного с базой данных, класс базы данных должен определять абстрактную функцию, которая не принимает аргументов и возвращает экземпляр класса DAO.

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

Примечание. Если ваше приложение выполняется в рамках одного процесса, то при создании экземпляра объекта AppDatabase следует использовать шаблон проектирования "Одиночка". Каждый экземпляр RoomDatabase требует значительных ресурсов, и вам вряд ли понадобится доступ к нескольким экземплярам в рамках одного процесса.

Если ваше приложение выполняется в нескольких процессах, добавьте enableMultiInstanceInvalidation() в вызов конструктора базы данных. Таким образом, если у вас есть экземпляр AppDatabase в каждом процессе, вы можете аннулировать общий файл базы данных в одном процессе, и это аннулирование автоматически распространится на экземпляры AppDatabase в других процессах.

Использование

После того как вы определили сущность данных, DAO и объект базы данных, вы можете использовать следующий код для создания экземпляра базы данных:

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

После этого вы можете использовать абстрактные функции из AppDatabase, чтобы получить экземпляр DAO. В свою очередь, вы можете использовать функции из экземпляра DAO для взаимодействия с базой данных:

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

Дополнительные ресурсы

Чтобы узнать больше о Room, ознакомьтесь со следующими ресурсами:

Образцы