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

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

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

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

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

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

Настроить

Чтобы использовать 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), которые предоставляют функции, позволяющие приложению запрашивать, обновлять, вставлять и удалять данные в базе данных.

Класс базы данных предоставляет приложению экземпляры объектов доступа к данным, связанных с этой базой данных. В свою очередь, приложение может использовать объекты доступа к данным, чтобы извлекать данные из базы данных в виде экземпляров связанных объектов сущностей данных. Приложение также может использовать определенные объекты данных для обновления строк в соответствующих таблицах или создания новых строк для вставки. На рисунке 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.

База данных

В приведенном ниже коде класс 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 в других процессах.

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

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

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, ознакомьтесь со следующими ресурсами:

Образцы