Подключение Room и создание локального хранилища в Android Studio
Короткий ответ: добавьте зависимости room-runtime, room-ktx и kapt room-compiler; опишите @Entity, @Dao и @Database; создайте репозиторий поверх DAO; интегрируйте с ViewModel через Flow/корутины. Ниже — компактный, применимый шаг за шагом план.
Что такое Room и когда его использовать
Room — обёртка над SQLite из Android Jetpack: статическая проверка SQL, преобразование в Kotlin‑объекты, поддержка корутин/Flow, миграций и тестирования. Используйте Room для персистентного хранилища (заметки, кэш API, офлайн‑данные) и сложных запросов (фильтры, JOIN). Для временных, in‑memory кешей достаточно ViewModel/State.
Room проверяет SQL на этапе компиляции — ошибки в названиях таблиц/полей вы увидите при сборке.
Быстрая настройка проекта
- В build.gradle (модуль app) подключите (Kotlin KTS‑пример):
val roomVersion = "2.6.1"
implementation("androidx.room:room-runtime:$roomVersion")
kapt("androidx.room:room-compiler:$roomVersion")
implementation("androidx.room:room-ktx:$roomVersion")
- Включите плагин kotlin-kapt в плагинах.
- Sync Now.
Частая ошибка — забыть kotlin-kapt или room-compiler: аннотации не сгенерируют код и сборка упадёт.
Шаги реализации (практика)
- Entity — таблица:
@Entity(tableName = "notes")
data class NoteEntity(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val title: String,
val content: String,
val createdAt: Long,
val updatedAt: Long? = null,
val isPinned: Boolean = false
)
- DAO — доступ к данным (Flow для наблюдения, suspend для операций):
@Dao
interface NoteDao {
@Query("SELECT * FROM notes ORDER BY isPinned DESC, updatedAt DESC")
fun getAllNotes(): Flow<List<NoteEntity>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertNote(note: NoteEntity): Long
// update, delete, getById...
}
- Database — точка входа:
@Database(entities = [NoteEntity::class], version = 1, exportSchema = true)
abstract class AppDatabase : RoomDatabase() {
abstract fun noteDao(): NoteDao
companion object {
fun getInstance(context: Context) = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app_database.db"
).build()
}
}
-
Миграции: при изменении схемы увеличьте version и добавьте Migration, либо используйте fallbackToDestructiveMigration() только для прототипов.
-
Репозиторий — инкапсулирует логику доступа:
class NoteRepository(private val dao: NoteDao) {
fun observeNotes() = dao.getAllNotes()
suspend fun createNote(...) = dao.insertNote(...)
}
- ViewModel: подписывайтесь на Flow в viewModelScope, обновляйте StateFlow/LiveData и запускайте DAO‑операции в корутинах.
Начните с минимальной схемы и простых миграций. Добавляйте TypeConverters только при необходимости (списки, LocalDateTime).
Интеграция, отладка и рабочие советы
- Вызывайте suspend‑методы в IO‑контексте (viewModelScope.launch(Dispatchers.IO)) или используйте room-ktx (для suspend Room сам переключает поток).
- Для отладки используйте Database Inspector в Android Studio (App Inspection).
- Хранение файла: data/data/
/databases/app_database.db — приватно для приложения.
Если увеличить version без миграций и без fallbackToDestructiveMigration(), приложение упадёт при обновлении.
Частые ошибки
- Забыт kotlin-kapt или room-compiler → сборка падает.
- Выполнение тяжёлых запросов на главном потоке → ANR.
- Игнорирование миграций → потеря данных или краш при обновлении.
- Излишнее SELECT * — передавайте только нужные поля (проекции/DTO).
FAQ
- Нужно ли всегда писать репозиторий? Рекомендуется: он упрощает замену источников данных и тестирование.
- Как хранить даты? Как правило — Long (timestamp) или ISO‑строка + TypeConverter для LocalDateTime.
- Можно ли использовать Room с Jetpack Compose? Да — подписывайтесь на StateFlow/LiveData и обновляйте UI реактивно.
Если нужно, могу прислать пример с @Relation, несколькими таблицами и примером миграции между версиями.