Эта практическая работа входит в курс «Основы Android Kotlin». Вы получите максимальную пользу от этого курса, если будете выполнять практические работы последовательно. Все практические работы курса перечислены на целевой странице практической работы «Основы Android Kotlin» .
Введение
В большинстве приложений есть данные, которые необходимо сохранять даже после того, как пользователь закрывает приложение. Например, приложение может хранить плейлист, список игровых предметов, записи расходов и доходов, каталог созвездий или данные о сне за определенный период времени. Обычно для хранения постоянных данных используется база данных.
Room
— это библиотека для работы с базами данных, входящая в состав Android Jetpack . Room
берёт на себя многие задачи по настройке и конфигурированию базы данных и позволяет вашему приложению взаимодействовать с ней, используя обычные вызовы функций. По сути, Room
— это уровень абстракции, работающий поверх базы данных SQLite. Терминология Room
и синтаксис запросов для более сложных запросов соответствуют модели SQLite.
На рисунке ниже показано, как база данных Room
вписывается в общую архитектуру, рекомендуемую в этом курсе.
Что вам уже следует знать
Вам должно быть знакомо:
- Создание базового пользовательского интерфейса (UI) для приложения Android
- Использование действий, фрагментов и представлений.
- Навигация между фрагментами и использование Safe Args (плагина Gradle) для передачи данных между фрагментами.
- Модели представлений, фабрики моделей представлений, а также
LiveData
и их наблюдатели. Эти темы, связанные с компонентами архитектуры, рассматриваются в предыдущей практической работе этого курса. - Базовые знания баз данных SQL и языка SQLite. Для быстрого ознакомления или освежения знаний см. SQLite Primer.
Чему вы научитесь
- Как создать и взаимодействовать с базой данных
Room
для сохранения данных. - Как создать класс данных, определяющий таблицу в базе данных.
- Как использовать объект доступа к данным (DAO) для сопоставления функций Kotlin с SQL-запросами.
- Как проверить работоспособность вашей базы данных.
Что ты будешь делать?
- Создайте базу данных
Room
с интерфейсом для данных о ночном сне. - Протестируйте базу данных, используя предоставленные тесты.
В этой лабораторной работе вы создадите часть приложения, работающую с базой данных, для отслеживания качества сна. Приложение использует базу данных для хранения данных о сне с течением времени.
Приложение имеет два экрана, представленных фрагментами, как показано на рисунке ниже.
На первом экране, показанном слева, есть кнопки для запуска и остановки отслеживания. На экране отображаются все данные о сне пользователя. Кнопка «Очистить» безвозвратно удаляет все данные, собранные приложением для пользователя.
Второй экран, показанный справа, предназначен для выбора оценки качества сна. В приложении оценка представлена в числовом виде. В целях разработки приложение отображает как значки лиц, так и их числовые эквиваленты.
Поток действий пользователя выглядит следующим образом:
- Пользователь открывает приложение и видит экран отслеживания сна.
- Пользователь нажимает кнопку «Старт» . Время начала фиксируется и отображается на экране. Кнопка «Старт» отключается, а кнопка «Стоп» активируется.
- Пользователь нажимает кнопку «Стоп» . Записывается время окончания и открывается экран качества сна.
- Пользователь выбирает значок качества сна. Экран закрывается, и на экране отслеживания отображаются время окончания сна и качество сна. Кнопка «Стоп» отключается, а кнопка «Старт» активируется. Приложение готово к следующей ночи.
- Кнопка «Очистить» активна, когда в базе данных есть данные. При нажатии кнопки «Очистить » все данные пользователя удаляются без возможности восстановления — сообщение «Вы уверены?» не появляется.
Это приложение использует упрощённую архитектуру, как показано ниже в контексте полной архитектуры. Приложение использует только следующие компоненты:
- Контроллер пользовательского интерфейса
- Просмотреть модель и
LiveData
- База данных A Room
Шаг 1: Загрузите и запустите стартовое приложение.
- Загрузите приложение TrackMySleepQuality-Starter с GitHub.
- Соберите и запустите приложение. Приложение отображает пользовательский интерфейс фрагмента
SleepTrackerFragment
, но не отображает данные. Кнопки не реагируют на нажатия.
Шаг 2: Проверьте стартовое приложение
- Взгляните на файлы Gradle:
- Файл проекта Gradle
В файлеbuild.gradle
уровня проекта обратите внимание на переменные, задающие версии библиотек. Версии, используемые в стартовом приложении, хорошо сочетаются друг с другом и хорошо работают с этим приложением. К моменту завершения этой лабораторной работы Android Studio может предложить вам обновить некоторые версии. Решение о том, обновлять или оставить версии, имеющиеся в приложении, зависит от вас. Если вы столкнётесь со «странными» ошибками компиляции, попробуйте использовать комбинацию версий библиотек, используемую в конечном решении . - Файл модуля Gradle. Обратите внимание на предоставленные зависимости для всех библиотек Android Jetpack, включая
Room
, а также зависимости для сопрограмм.
- Взгляните на пакеты и пользовательский интерфейс. Приложение структурировано по функциональным возможностям. Пакет содержит файлы-заглушки, в которые вы будете добавлять код в ходе этой серии практических занятий.
- Пакет
database
для всего кода , относящегося к базе данныхRoom
. - Пакеты
sleepquality
иsleeptracker
содержат фрагмент, модель представления и фабрику моделей представления для каждого экрана.
- Взгляните на файл
Util.kt
, содержащий функции для отображения данных о качестве сна. Часть кода закомментирована, поскольку ссылается на модель представления, которую вы создадите позже. - Взгляните на папку androidTest (
SleepDatabaseTest.kt
). Этот тест поможет вам проверить, работает ли база данных должным образом.
В Android данные представлены в классах данных, а доступ к ним и их изменение осуществляются с помощью вызовов функций. Однако в мире баз данных необходимы сущности и запросы .
- Сущность представляет собой объект или понятие и его свойства, хранящиеся в базе данных. Класс сущности определяет таблицу, и каждый экземпляр этого класса представляет строку в таблице. Каждое свойство определяет столбец. В вашем приложении сущность будет хранить информацию о сне за ночь.
- Запрос — это запрос данных или информации из таблицы базы данных или комбинации таблиц, а также запрос на выполнение действия с данными. Обычно запросы предназначены для получения, добавления и обновления сущностей. Например, можно запросить все зарегистрированные ночи сна, отсортированные по времени начала.
Room
выполняет всю сложную работу по переходу от классов данных Kotlin к сущностям, которые можно хранить в таблицах SQLite, и от объявлений функций к запросам SQL.
Необходимо определить каждую сущность как аннотированный класс данных, а взаимодействия — как аннотированный интерфейс, объект доступа к данным (DAO) . Room
использует эти аннотированные классы для создания таблиц в базе данных и запросов к ней.
Шаг 1: Создание объекта SleepNight
В этой задаче вы определяете одну ночь сна как аннотированный класс данных.
Для одной ночи сна вам необходимо записать время начала, время окончания и оценку качества.
И вам понадобится идентификатор, чтобы однозначно идентифицировать ночь.
- В пакете
database
найдите и откройте файлSleepNight.kt
. - Создайте класс данных
SleepNight
с параметрами для идентификатора, времени начала (в миллисекундах), времени окончания (в миллисекундах) и числовой оценки качества сна.
- Вам необходимо инициализировать
sleepQuality
, установив его на-1
, что будет означать, что данные о качестве не были собраны. - Вам также необходимо инициализировать время окончания. Установите его равным времени начала, чтобы обозначить, что время окончания ещё не записано.
data class SleepNight(
var nightId: Long = 0L,
val startTimeMilli: Long = System.currentTimeMillis(),
var endTimeMilli: Long = startTimeMilli,
var sleepQuality: Int = -1
)
- Перед объявлением класса добавьте аннотацию
@Entity
к классу данных. Назовите таблицуdaily_sleep_quality_table
. АргументtableName
необязателен, но рекомендуется. Информация о других аргументах представлена в документации.
При появлении запроса импортируйтеEntity
и все остальные аннотации из библиотекиandroidx
.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)
- Чтобы определить
nightId
как первичный ключ, добавьте к свойствуnightId
аннотацию@PrimaryKey
. Установите параметрautoGenerate
вtrue
, чтобыRoom
генерировал идентификатор для каждой сущности. Это гарантирует уникальность идентификатора для каждой ночи.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...
- Добавьте аннотацию к оставшимся свойствам с помощью
@ColumnInfo
. Настройте имена свойств, используя параметры, как показано ниже.
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,
@ColumnInfo(name = "start_time_milli")
val startTimeMilli: Long = System.currentTimeMillis(),
@ColumnInfo(name = "end_time_milli")
var endTimeMilli: Long = startTimeMilli,
@ColumnInfo(name = "quality_rating")
var sleepQuality: Int = -1
)
- Скомпилируйте и запустите свой код, чтобы убедиться в отсутствии ошибок.
В этой задаче вы определите объект доступа к данным (DAO). В Android DAO предоставляет удобные методы для добавления, удаления и обновления базы данных.
При использовании базы данных Room
вы обращаетесь к ней, определяя и вызывая функции Kotlin в коде. Эти функции Kotlin сопоставляются с SQL-запросами. Вы определяете эти сопоставления в DAO с помощью аннотаций, а Room
создаёт необходимый код.
Представьте себе DAO как определение настраиваемого интерфейса для доступа к вашей базе данных.
Для распространённых операций с базой данных библиотека Room
предоставляет удобные аннотации, такие как @Insert
, @Delete
и @Update
. Для всего остального есть аннотация @Query
. Вы можете написать любой запрос, поддерживаемый SQLite.
В качестве дополнительного бонуса, когда вы создаете запросы в Android Studio, компилятор проверяет ваши SQL-запросы на наличие синтаксических ошибок.
Для базы данных с данными о сне вам необходимо иметь возможность выполнять следующие действия:
- Вставьте новые ночи.
- Обновите существующую ночь, чтобы обновить время окончания и рейтинг качества.
- Получите конкретную ночь в зависимости от ее тональности.
- Получите все ночи , чтобы вы могли их отобразить.
- Получите последнюю ночь.
- Удалить все записи в базе данных.
Шаг 1: Создайте SleepDatabase DAO
- В пакете
database
откройтеSleepDatabaseDao.kt
. - Обратите внимание, что
interface
SleepDatabaseDao
аннотирован@Dao
. Все объекты DAO должны быть аннотированы ключевым словом@Dao
.
@Dao
interface SleepDatabaseDao {}
- Внутри тела интерфейса добавьте аннотацию
@Insert
. Под@Insert
добавьте функциюinsert()
, которая принимает экземпляр классаEntity
SleepNight
в качестве своего аргумента.
Вот и всё.Room
сгенерирует весь необходимый код для добавленияSleepNight
в базу данных. При вызовеinsert()
из кода KotlinRoom
выполняет SQL-запрос для добавления сущности в базу данных. (Примечание: вы можете назвать эту функцию как угодно.)
@Insert
fun insert(night: SleepNight)
- Добавьте аннотацию
@Update
с функциейupdate()
для одногоSleepNight
. Обновляемая сущность — это сущность с тем же ключом, что и переданная. Вы можете обновить некоторые или все остальные свойства сущности.
@Update
fun update(night: SleepNight)
Для оставшейся функциональности нет удобной аннотации, поэтому вам придется использовать аннотацию @Query
и предоставлять запросы SQLite.
- Добавьте аннотацию
@Query
с функциейget()
, которая принимаетLong
key
Аргумент и возвращаетSleepNight
, допускающий значение NULL. Если параметр отсутствует, вы увидите ошибку.
@Query
fun get(key: Long): SleepNight?
- Запрос передается в виде строкового параметра аннотации. Добавьте параметр в
@Query
. Сделайте егоString
, представляющей собой запрос SQLite.
- Выберите все столбцы из таблицы
daily_sleep_quality_table
-
WHERE
nightId
соответствуетkey
аргументу :.
Обратите внимание на:key
. Двоеточие в запросе используется для ссылки на аргументы функции.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
- Добавьте ещё один
@Query
с функциейclear()
и SQLite-запросом дляDELETE
всех данных из таблицыdaily_sleep_quality_table
. Этот запрос не удаляет саму таблицу.
Аннотация@Delete
удаляет один элемент, и вы могли бы использовать@Delete
и предоставить список ночей для удаления. Недостаток заключается в том, что вам нужно получить или знать содержимое таблицы. Аннотация@Delete
отлично подходит для удаления отдельных записей, но неэффективна для удаления всех записей из таблицы.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
- Добавьте
@Query
с функциейgetTonight()
. Сделайте так, чтобыSleepNight
, возвращаемый функциейgetTonight()
допускал значение NULL, чтобы функция могла обрабатывать случай, когда таблица пуста. (Таблица пуста в начале и после очистки данных.)
Чтобы получить значение «tonight» из базы данных, напишите SQLite-запрос, который вернет первый элемент списка результатов, отсортированного поnightId
в порядке убывания. ИспользуйтеLIMIT 1
чтобы вернуть только один элемент.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?
- Добавьте
@Query
с функциейgetAllNights()
:
- Запрос SQLite должен вернуть все столбцы из
daily_sleep_quality_table
, упорядоченные по убыванию. - Метод
getAllNights()
возвращает список сущностейSleepNight
в видеLiveData
.Room
обновляет этиLiveData
, что означает, что вам нужно явно получить данные только один раз. - Возможно, вам потребуется импортировать
LiveData
изandroidx.lifecycle.LiveData
.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
fun getAllNights(): LiveData<List<SleepNight>>
- Хотя вы не увидите никаких видимых изменений, запустите приложение, чтобы убедиться в отсутствии ошибок.
В этой задаче вы создаете базу данных Room
, которая использует Entity
и DAO, созданные вами в предыдущей задаче.
Вам необходимо создать абстрактный класс-держатель базы данных с аннотацией @Database
. Этот класс имеет один метод, который либо создаёт экземпляр базы данных, если она не существует, либо возвращает ссылку на существующую базу данных.
Получение базы данных Room
немного сложнее, поэтому вот общий процесс, прежде чем вы начнете работать с кодом:
- Создайте
public abstract
класс,extends RoomDatabase
. Этот класс будет выполнять функцию хранилища базы данных. Класс является абстрактным, посколькуRoom
создаёт реализацию автоматически. - Добавьте к классу аннотацию
@Database
. В аргументах объявите сущности для базы данных и укажите номер версии. - Внутри объекта-
companion
определите абстрактный метод или свойство, возвращающееSleepDatabaseDao
.Room
сгенерирует тело автоматически. - Вам нужен только один экземпляр базы данных
Room
для всего приложения, поэтому сделайтеRoomDatabase
одиночным экземпляром. - Используйте конструктор баз данных
Room
для создания базы данных только в том случае, если она не существует. В противном случае верните существующую базу данных.
Шаг 1: Создание базы данных
- В пакете
database
откройтеSleepDatabase.kt
. - В файле создайте
abstract
классSleepDatabase
, который расширяетRoomDatabase
.
Добавьте к классу аннотацию@Database
.
@Database()
abstract class SleepDatabase : RoomDatabase() {}
- Вы увидите ошибку из-за отсутствующих сущностей и параметров версии. Аннотация
@Database
требует нескольких аргументов, чтобыRoom
мог создать базу данных.
- Укажите
SleepNight
как единственный элемент со спискомentities
. - Установите
version
1
При каждом изменении схемы вам придется увеличивать номер версии. - Установите
exportSchema
наfalse
, чтобы не сохранять резервные копии истории версий схемы.
entities = [SleepNight::class], version = 1, exportSchema = false
- Базе данных необходимо знать о DAO. В теле класса объявите абстрактное значение, возвращающее
SleepDatabaseDao
. Можно иметь несколько DAO.
abstract val sleepDatabaseDao: SleepDatabaseDao
- Ниже определите
companion
объект. Этот сопутствующий объект позволяет клиентам получать доступ к методам создания или получения базы данных без создания экземпляра класса. Поскольку единственное назначение этого класса — предоставление базы данных, нет смысла создавать его экземпляр.
companion object {}
- Внутри объекта
companion
объявите частную переменнуюINSTANCE
для базы данных, допускающую значение NULL, и инициализируйте её значениемnull
. ПеременнаяINSTANCE
сохранит ссылку на базу данных после её создания. Это поможет избежать многократного открытия подключений к базе данных, что требует больших затрат.
Добавьте аннотацию @Volatile
к INSTANCE
. Значение переменной volatile никогда не будет кэшироваться, а все операции записи и чтения будут выполняться в основную память и из неё. Это помогает гарантировать, что значение INSTANCE
всегда актуально и одинаково для всех потоков выполнения. Это означает, что изменения, внесённые одним потоком в INSTANCE
, немедленно видны всем остальным потокам, и вы не столкнётесь с ситуацией, когда, скажем, два потока обновляют одну и ту же сущность в кэше, что могло бы создать проблему.
@Volatile
private var INSTANCE: SleepDatabase? = null
- Ниже
INSTANCE
, всё ещё внутри объектаcompanion
, определите методgetInstance()
с параметромContext
, который понадобится конструктору базы данных. Возвращает типSleepDatabase
. Вы увидите ошибку, посколькуgetInstance()
пока ничего не возвращает.
fun getInstance(context: Context): SleepDatabase {}
- Внутри
getInstance()
добавьте блокsynchronized{}
. Передайтеthis
, чтобы получить доступ к контексту.
Несколько потоков могут одновременно запрашивать экземпляр базы данных, что приводит к появлению двух баз данных вместо одной. Эта проблема вряд ли возникнет в этом примере приложения, но возможна в более сложном приложении. Обёртывание кода дляsynchronized
базы данных означает, что только один поток выполнения одновременно может войти в этот блок кода, что гарантирует однократную инициализацию базы данных.
synchronized(this) {}
- Внутри блока synchronized скопируйте текущее значение
INSTANCE
в локальную переменнуюinstance
. Это позволит воспользоваться функцией Smart Cast , которая доступна только для локальных переменных.
var instance = INSTANCE
- Внутри
synchronized
блокаreturn instance
в концеsynchronized
блока. Игнорируйте ошибку несоответствия возвращаемого типа; после завершения вы больше никогда не вернёте значение null.
return instance
- Над оператором
return
добавьте операторif
, чтобы проверить, является лиinstance
null, то есть база данных еще не существует.
if (instance == null) {}
- Если
instance
равенnull
, используйте конструктор баз данных для получения базы данных. В теле оператораif
вызовитеRoom.databaseBuilder
и укажите переданный вами контекст, класс базы данных и имя базы данныхsleep_history_database
. Чтобы устранить ошибку, вам потребуется добавить стратегию миграции иbuild()
в следующих шагах.
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database")
- Добавьте требуемую стратегию миграции в конструктор. Используйте
.fallbackToDestructiveMigration()
.
Обычно вам потребуется предоставить объект миграции со стратегией миграции на случай изменения схемы. Объект миграции — это объект, который определяет, как все строки старой схемы преобразуются в строки новой схемы, чтобы данные не терялись. Миграция выходит за рамки данной практической работы. Простое решение — удалить и пересоздать базу данных, что означает потерю данных.
.fallbackToDestructiveMigration()
- Наконец, вызовите
.build()
.
.build()
- Назначьте
INSTANCE = instance
как последний шаг внутри оператораif
.
INSTANCE = instance
- Ваш окончательный код должен выглядеть так:
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {
abstract val sleepDatabaseDao: SleepDatabaseDao
companion object {
@Volatile
private var INSTANCE: SleepDatabase? = null
fun getInstance(context: Context): SleepDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}
- Создайте и запустите свой код.
Теперь у вас есть все необходимые элементы для работы с базой данных Room
. Этот код компилируется и запускается, но вы не можете точно сказать, работает ли он. Поэтому сейчас самое время добавить несколько простых тестов.
Шаг 2: Тестирование SleepDatabase
На этом этапе вы запускаете предоставленные тесты для проверки работоспособности вашей базы данных. Это помогает убедиться в её работоспособности перед началом разработки. Предоставленные тесты являются базовыми. Для производственного приложения вам потребуется протестировать все функции и запросы во всех DAO.
Стартовое приложение содержит папку androidTest . Эта папка androidTest содержит модульные тесты, использующие инструментарий Android. Это замысловатый способ сказать, что для тестов требуется фреймворк Android, поэтому их нужно запускать на физическом или виртуальном устройстве. Конечно, вы также можете создавать и запускать чистые модульные тесты, не использующие фреймворк Android.
- В Android Studio в папке androidTest откройте файл SleepDatabaseTest .
- Чтобы раскомментировать код, выделите весь закомментированный код и нажмите сочетание клавиш
Cmd+/
илиControl+/
. - Взгляните на файл.
Вот краткий обзор тестового кода, поскольку это еще один фрагмент кода, который можно использовать повторно:
-
SleepDabaseTest
— это тестовый класс . - Аннотация
@RunWith
идентифицирует исполнителя тестов — программу, которая настраивает и выполняет тесты. - Во время настройки выполняется функция с аннотацией
@Before
, которая создаётSleepDatabase
в памяти с объектомSleepDatabaseDao
. «В памяти» означает, что эта база данных не сохраняется в файловой системе и будет удалена после выполнения тестов. - Кроме того, при построении базы данных в памяти код вызывает другой специфичный для теста метод —
allowMainThreadQueries
. По умолчанию при попытке выполнить запросы в основном потоке возникает ошибка. Этот метод позволяет запускать тесты в основном потоке, что следует делать только во время тестирования. - В тестовом методе, аннотированном
@Test
, вы создаёте, вставляете и извлекаетеSleepNight
и проверяете их идентичность. Если что-то пойдёт не так, выдаётся исключение. В реальном тесте у вас будет несколько@Test
методы. - После завершения тестирования выполняется функция, аннотированная
@After
, для закрытия базы данных.
- Щелкните правой кнопкой мыши тестовый файл на панели «Проект» и выберите «Запустить «SleepDatabaseTest» .
- После выполнения тестов проверьте на панели SleepDatabaseTest , что все тесты пройдены.
Поскольку все тесты пройдены, теперь вы знаете несколько вещей:
- База данных создается корректно.
- Вы можете вставить
SleepNight
в базу данных. - Вы можете вернуть
SleepNight
. -
SleepNight
имеет правильное значение качества.
Проект Android Studio: TrackMySleepQualityRoomAndTesting
При тестировании базы данных необходимо проверить все методы, определённые в DAO. Для завершения тестирования добавьте и выполните тесты для проверки остальных методов DAO.
- Определите таблицы как классы данных, аннотированные
@Entity
. Свойства, аннотированные@ColumnInfo
, определите как столбцы в таблицах. - Определите объект доступа к данным (DAO) как интерфейс, аннотированный
@Dao
. DAO сопоставляет функции Kotlin с запросами к базе данных. - Используйте аннотации для определения функций
@Insert
,@Delete
и@Update
. - Используйте аннотацию
@Query
со строкой запроса SQLite в качестве параметра для любых других запросов. - Создайте абстрактный класс, имеющий функцию
getInstance()
, которая возвращает базу данных. - Используйте инструментированные тесты для проверки корректной работы вашей базы данных и DAO. Вы можете использовать предоставленные тесты в качестве шаблона.
Курс Udacity:
Документация для разработчиков Android:
-
RoomDatabase
-
Database
(аннотации) - Вы можете использовать необработанные запросы с
Room
-
Roomdatabase.Builder
- Тестирование обучения
- Класс
SQLiteDatabase
-
Dao
- Библиотека персистентности
Room
Другая документация и статьи:
В этом разделе перечислены возможные домашние задания для студентов, работающих над этой лабораторной работой в рамках курса, проводимого преподавателем. Преподаватель должен выполнить следующие действия:
- При необходимости задавайте домашнее задание.
- Объясните учащимся, как следует сдавать домашние задания.
- Оцените домашние задания.
Преподаватели могут использовать эти предложения так часто или редко, как пожелают, и могут свободно задавать любые другие домашние задания, которые они сочтут подходящими.
Если вы работаете с этой лабораторной работой самостоятельно, можете использовать эти домашние задания для проверки своих знаний.
Ответьте на эти вопросы
Вопрос 1
Как указать, что класс представляет собой сущность для хранения в базе данных Room
?
- Сделайте так, чтобы класс расширял
DatabaseEntity
. - Добавьте к классу аннотацию
@Entity
. - Добавьте к классу аннотацию
@Database
. - Сделайте так, чтобы класс расширял
RoomEntity
, а также аннотируйте класс@Room
.
Вопрос 2
DAO (объект доступа к данным) — это интерфейс, который Room
использует для сопоставления функций Kotlin с запросами к базе данных.
Как указать, что интерфейс представляет собой DAO для базы данных Room
?
- Сделайте так, чтобы интерфейс расширял
RoomDAO
. - Сделайте так, чтобы интерфейс расширял
EntityDao
, а затем реализуйте методDaoConnection()
. - Добавьте к интерфейсу аннотацию
@Dao
. - Добавьте аннотацию к интерфейсу с помощью
@RoomConnection
.
Вопрос 3
Какие из следующих утверждений верны для базы данных Room
? Выберите все подходящие варианты.
- Таблицы для базы данных
Room
можно определить как аннотированные классы данных. - Если вы возвращаете
LiveData
из запроса,Room
будет обновлятьLiveData
, еслиLiveData
изменится. - Каждая база данных
Room
должна иметь один и только один DAO. - Чтобы идентифицировать класс как базу данных
Room
, сделайте его подклассомRoomDatabase
и аннотируйте его@Database
.
Вопрос 4
Какие из следующих аннотаций можно использовать в интерфейсе @Dao
? Выберите все подходящие варианты.
-
@Get
-
@Update
-
@Insert
-
@Query
Вопрос 5
Как проверить работоспособность вашей базы данных? Выберите все подходящие варианты.
- Напишите инструментированные тесты.
- Продолжайте писать и запускать приложение, пока оно не отобразит данные.
- Замените вызовы методов в интерфейсе DAO вызовами эквивалентных методов в классе
Entity
. - Запустите функцию
verifyDatabase()
предоставленную библиотекойRoom
.
Перейти к следующему уроку:
Ссылки на другие практические занятия по этому курсу см. на целевой странице практических занятий по основам Android Kotlin .
Эта практическая работа входит в курс «Основы Android Kotlin». Вы получите максимальную пользу от этого курса, если будете выполнять практические работы последовательно. Все практические работы курса перечислены на целевой странице практической работы «Основы Android Kotlin» .
Введение
В большинстве приложений есть данные, которые необходимо сохранять даже после того, как пользователь закрывает приложение. Например, приложение может хранить плейлист, список игровых предметов, записи расходов и доходов, каталог созвездий или данные о сне за определенный период времени. Обычно для хранения постоянных данных используется база данных.
Room
— это библиотека для работы с базами данных, входящая в состав Android Jetpack . Room
берёт на себя многие задачи по настройке и конфигурированию базы данных и позволяет вашему приложению взаимодействовать с ней, используя обычные вызовы функций. По сути, Room
— это уровень абстракции, работающий поверх базы данных SQLite. Терминология Room
и синтаксис запросов для более сложных запросов соответствуют модели SQLite.
На рисунке ниже показано, как база данных Room
вписывается в общую архитектуру, рекомендуемую в этом курсе.
Что вам уже следует знать
Вам должно быть знакомо:
- Создание базового пользовательского интерфейса (UI) для приложения Android
- Использование действий, фрагментов и представлений.
- Навигация между фрагментами и использование Safe Args (плагина Gradle) для передачи данных между фрагментами.
- Модели представлений, фабрики моделей представлений, а также
LiveData
и их наблюдатели. Эти темы, связанные с компонентами архитектуры, рассматриваются в предыдущей практической работе этого курса. - Базовые знания баз данных SQL и языка SQLite. Для быстрого ознакомления или освежения знаний см. SQLite Primer.
Чему вы научитесь
- Как создать и взаимодействовать с базой данных
Room
для сохранения данных. - Как создать класс данных, определяющий таблицу в базе данных.
- Как использовать объект доступа к данным (DAO) для сопоставления функций Kotlin с SQL-запросами.
- Как проверить работоспособность вашей базы данных.
Что ты будешь делать?
- Создайте базу данных
Room
с интерфейсом для данных о ночном сне. - Протестируйте базу данных, используя предоставленные тесты.
В этой лабораторной работе вы создадите часть приложения, работающую с базой данных, для отслеживания качества сна. Приложение использует базу данных для хранения данных о сне с течением времени.
Приложение имеет два экрана, представленных фрагментами, как показано на рисунке ниже.
На первом экране, показанном слева, есть кнопки для запуска и остановки отслеживания. На экране отображаются все данные о сне пользователя. Кнопка «Очистить» безвозвратно удаляет все данные, собранные приложением для пользователя.
Второй экран, показанный справа, предназначен для выбора оценки качества сна. В приложении оценка представлена в числовом виде. В целях разработки приложение отображает как значки лиц, так и их числовые эквиваленты.
Поток действий пользователя выглядит следующим образом:
- Пользователь открывает приложение и видит экран отслеживания сна.
- Пользователь нажимает кнопку «Старт» . Время начала фиксируется и отображается на экране. Кнопка «Старт» отключается, а кнопка «Стоп» активируется.
- Пользователь нажимает кнопку «Стоп» . Записывается время окончания и открывается экран качества сна.
- Пользователь выбирает значок качества сна. Экран закрывается, и на экране отслеживания отображаются время окончания сна и качество сна. Кнопка «Стоп» отключается, а кнопка «Старт» активируется. Приложение готово к следующей ночи.
- Кнопка «Очистить» активна, когда в базе данных есть данные. При нажатии кнопки «Очистить » все данные пользователя удаляются без возможности восстановления — сообщение «Вы уверены?» не появляется.
Это приложение использует упрощённую архитектуру, как показано ниже в контексте полной архитектуры. Приложение использует только следующие компоненты:
- Контроллер пользовательского интерфейса
- Просмотреть модель и
LiveData
- База данных A Room
Шаг 1: Загрузите и запустите стартовое приложение.
- Загрузите приложение TrackMySleepQuality-Starter с GitHub.
- Соберите и запустите приложение. Приложение отображает пользовательский интерфейс фрагмента
SleepTrackerFragment
, но не отображает данные. Кнопки не реагируют на нажатия.
Шаг 2: Проверьте стартовое приложение
- Взгляните на файлы Gradle:
- Файл проекта Gradle
В файлеbuild.gradle
уровня проекта обратите внимание на переменные, задающие версии библиотек. Версии, используемые в стартовом приложении, хорошо сочетаются друг с другом и хорошо работают с этим приложением. К моменту завершения этой лабораторной работы Android Studio может предложить вам обновить некоторые версии. Решение о том, обновлять или оставить версии, имеющиеся в приложении, зависит от вас. Если вы столкнётесь со «странными» ошибками компиляции, попробуйте использовать комбинацию версий библиотек, используемую в конечном решении . - Файл модуля Gradle. Обратите внимание на предоставленные зависимости для всех библиотек Android Jetpack, включая
Room
, а также зависимости для сопрограмм.
- Взгляните на пакеты и пользовательский интерфейс. Приложение структурировано по функциональным возможностям. Пакет содержит файлы-заглушки, в которые вы будете добавлять код в ходе этой серии практических занятий.
- Пакет
database
для всего кода , относящегося к базе данныхRoom
. - Пакеты
sleepquality
иsleeptracker
содержат фрагмент, модель представления и фабрику моделей представления для каждого экрана.
- Взгляните на файл
Util.kt
, содержащий функции для отображения данных о качестве сна. Часть кода закомментирована, поскольку ссылается на модель представления, которую вы создадите позже. - Взгляните на папку androidTest (
SleepDatabaseTest.kt
). Этот тест поможет вам проверить, работает ли база данных должным образом.
В Android данные представлены в классах данных, а доступ к ним и их изменение осуществляются с помощью вызовов функций. Однако в мире баз данных необходимы сущности и запросы .
- Сущность представляет собой объект или понятие и его свойства, хранящиеся в базе данных. Класс сущности определяет таблицу, и каждый экземпляр этого класса представляет строку в таблице. Каждое свойство определяет столбец. В вашем приложении сущность будет хранить информацию о сне за ночь.
- Запрос — это запрос данных или информации из таблицы базы данных или комбинации таблиц, а также запрос на выполнение действия с данными. Обычно запросы предназначены для получения, добавления и обновления сущностей. Например, можно запросить все зарегистрированные ночи сна, отсортированные по времени начала.
Room
выполняет всю сложную работу по переходу от классов данных Kotlin к сущностям, которые можно хранить в таблицах SQLite, и от объявлений функций к запросам SQL.
Необходимо определить каждую сущность как аннотированный класс данных, а взаимодействия — как аннотированный интерфейс, объект доступа к данным (DAO) . Room
использует эти аннотированные классы для создания таблиц в базе данных и запросов к ней.
Шаг 1: Создание объекта SleepNight
В этой задаче вы определяете одну ночь сна как аннотированный класс данных.
Для одной ночи сна вам необходимо записать время начала, время окончания и оценку качества.
И вам понадобится идентификатор, чтобы однозначно идентифицировать ночь.
- В пакете
database
найдите и откройте файлSleepNight.kt
. - Создайте класс данных
SleepNight
с параметрами для идентификатора, времени начала (в миллисекундах), времени окончания (в миллисекундах) и числовой оценки качества сна.
- Вам необходимо инициализировать
sleepQuality
, установив его на-1
, что будет означать, что данные о качестве не были собраны. - Вам также необходимо инициализировать время окончания. Установите его равным времени начала, чтобы обозначить, что время окончания ещё не записано.
data class SleepNight(
var nightId: Long = 0L,
val startTimeMilli: Long = System.currentTimeMillis(),
var endTimeMilli: Long = startTimeMilli,
var sleepQuality: Int = -1
)
- Перед объявлением класса аннотируйте класс данных
@Entity
. Назовите таблицуdaily_sleep_quality_table
. Аргумент дляtableName
является необязательным, но рекомендуется. Вы можете найти другие аргументы в документации.
Если будет предложено, импортEntity
и все другие аннотации из библиотекиandroidx
.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)
- Чтобы идентифицировать
nightId
в качестве основного ключа, аннотируйтеnightId
недвижимость@PrimaryKey
. Установите параметрautoGenerate
вtrue
, чтобыRoom
генерировала идентификатор для каждого объекта. Это гарантирует, что идентификатор для каждой ночи уникален.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...
- Аннотировать оставшиеся свойства
@ColumnInfo
. Настройте имена свойств, используя параметры, как показано ниже.
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,
@ColumnInfo(name = "start_time_milli")
val startTimeMilli: Long = System.currentTimeMillis(),
@ColumnInfo(name = "end_time_milli")
var endTimeMilli: Long = startTimeMilli,
@ColumnInfo(name = "quality_rating")
var sleepQuality: Int = -1
)
- Создайте и запустите свой код, чтобы убедиться, что у него нет ошибок.
В этой задаче вы определяете объект доступа данных (DAO). На Android DAO предоставляет удобные методы для вставки, удаления и обновления базы данных.
Когда вы используете базу данных Room
, вы запросите базу данных, определяя и вызывая функции Kotlin в вашем коде. Эти функции Kotlin отображают запросы SQL. Вы определяете эти отображения в DAO, используя аннотации, а Room
создает необходимый код.
Думайте о DAO как о определении пользовательского интерфейса для доступа к вашей базе данных.
Для общих операций базы данных библиотека Room
предоставляет удобные аннотации, такие как @Insert
, @Delete
и @Update
. Для всего остального есть аннотация @Query
. Вы можете написать любой запрос, который поддерживается SQLite.
В качестве дополнительного бонуса, когда вы создаете свои запросы в Android Studio, компилятор проверяет ваши запросы SQL на наличие синтаксических ошибок.
Для базы данных для сна по ночам сна, вам нужно иметь возможность сделать следующее:
- Вставьте новые ночи.
- Обновите существующую ночь, чтобы обновить время окончания и качественный рейтинг.
- Получите конкретную ночь на основе его ключа.
- Получите все ночи , чтобы вы могли отобразить их.
- Получите последнюю ночь.
- Удалить все записи в базе данных.
Шаг 1: Создайте DAO SleepDatabase DAO
- В пакете
database
OpenSleepDatabaseDao.kt
. - Обратите внимание, что
interface
SleepDatabaseDao
аннотирован с@Dao
. Все DAO должны быть аннотированы с ключевым словом@Dao
.
@Dao
interface SleepDatabaseDao {}
- Внутри корпуса интерфейса добавьте аннотацию
@Insert
. Ниже@Insert
добавьте функциюinsert()
, которая принимает экземпляр классаEntity
ClassSleepNight
как его аргумент.
Вот и все.Room
будет генерировать весь необходимый код для вставкиSleepNight
в базу данных. Когда вы вызовитеinsert()
из кода Kotlin,Room
выполняет SQL -запрос, чтобы вставить объект в базу данных. (Примечание: вы можете вызвать функцию все, что хотите.)
@Insert
fun insert(night: SleepNight)
- Добавьте аннотацию
@Update
с функциейupdate()
для однойSleepNight
. Обновленная сущность - это сущность, которая имеет тот же ключ, что и тот, который передается. Вы можете обновить некоторые или все другие свойства объекта.
@Update
fun update(night: SleepNight)
Для оставшейся функциональности нет удобной аннотации, поэтому вы должны использовать аннотацию @Query
и снабжение SQLite.
- Добавьте аннотацию
@Query
с функциейget()
, которая занимаетLong
key
Аргумент и возвращает нулевуюSleepNight
. Вы увидите ошибку для отсутствующего параметра.
@Query
fun get(key: Long): SleepNight?
- Запрос поставляется в виде струнного параметра для аннотации. Добавьте параметр в
@Query
. Сделайте этоString
, которая является запросом SQLite.
- Выберите все столбцы в
daily_sleep_quality_table
-
WHERE
nightId
соответствует:key
аргумент.
Обратите внимание:key
. Вы используете нотацию толстой кишки в запросе для ссылки на аргументы в функции.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
- Добавьте еще один
@Query
с функциейclear()
и запросом SQLite, чтобыDELETE
все изdaily_sleep_quality_table
. Этот запрос не удаляет саму таблицу.
Аннотация@Delete
удаляет один элемент, и вы можете использовать@Delete
и предоставить список ночей для удаления. Недостаток в том, что вам нужно получить или знать, что находится в таблице. Аннотация@Delete
отлично подходит для удаления конкретных записей, но не эффективна для очистки всех записей из таблицы.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
- Добавьте
@Query
с функциейgetTonight()
. СделайтеSleepNight
возвращаемуюgetTonight()
, чтобы быть нулевой, чтобы функция могла справиться с случаем, когда таблица пуста. (Таблица пуста в начале, и после очистки данных.)
Чтобы получить «сегодня вечером» из базы данных, напишите запрос SQLite, который возвращает первый элемент списка результатов, упорядоченныхnightId
в порядке убывания. ИспользуйтеLIMIT 1
, чтобы вернуть только один элемент.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?
- Добавьте
@Query
с функциейgetAllNights()
:
- Попросите запрос SQLite вернуть все столбцы из
daily_sleep_quality_table
, упорядоченного в порядке убывания. - Получите
getAllNights()
вернуть список сущностейSleepNight
в качествеLiveData
.Room
держит этуLiveData
обновленную для вас, что означает, что вам нужно явно получить данные только один раз. - Возможно, вам потребуется импортировать
LiveData
изandroidx.lifecycle.LiveData
.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
fun getAllNights(): LiveData<List<SleepNight>>
- Хотя вы не увидите никаких видимых изменений, запустите свое приложение, чтобы убедиться, что у него нет ошибок.
В этой задаче вы создаете базу данных Room
, которая использует Entity
и DAO, которые вы создали в предыдущей задаче.
Вам нужно создать класс держателя абстрактного базы данных, аннотированный @Database
. Этот класс имеет один метод, который либо создает экземпляр базы данных, если база данных не существует, либо возвращает ссылку на существующую базу данных.
Получение базы данных Room
немного задействовано, поэтому вот общий процесс, прежде чем начать с кода:
- Создайте
public abstract
класс, которыйextends RoomDatabase
. Этот класс должен действовать как держатель базы данных. Класс абстрактный, потому чтоRoom
создает реализацию для вас. - Аннотируйте класс с
@Database
. В аргументах объявьте объекты для базы данных и установите номер версии. - Внутри
companion
объекта определите абстрактный метод или свойство, которое возвращаетSleepDatabaseDao
.Room
будет генерировать для вас тело. - Вам нужен только один экземпляр базы данных
Room
для всего приложения, так что сделайтеRoomDatabase
синглтоном. - Используйте застройщик базы данных
Room
, чтобы создать базу данных, только если база данных не существует. В противном случае верните существующую базу данных.
Шаг 1: Создайте базу данных
- В пакете
database
OpenSleepDatabase.kt
. - В файле создайте
abstract
класс под названиемSleepDatabase
, который расширяетRoomDatabase
.
Аннотируйте класс с@Database
.
@Database()
abstract class SleepDatabase : RoomDatabase() {}
- Вы увидите ошибку для пропущенных объектов и параметров версии. Аннотация
@Database
требует нескольких аргументов, так чтоRoom
может построить базу данных.
- Предоставьте ночью
SleepNight
как единственный предмет со спискомentities
. - Установите
version
как1
Всякий раз, когда вы меняете схему, вам придется увеличить номер версии. - Установите
exportSchema
вfalse
, чтобы не сохранить резервные копии истории версий схемы.
entities = [SleepNight::class], version = 1, exportSchema = false
- База данных должна знать о DAO. Внутри тела класса объявите абстрактную ценность, которая возвращает
SleepDatabaseDao
. Вы можете иметь несколько DAO.
abstract val sleepDatabaseDao: SleepDatabaseDao
- Ниже определить
companion
. Спутниковый объект позволяет клиентам получить доступ к методам создания или получения базы данных без создания подготовки к классу. Поскольку единственной целью этого класса является предоставление базы данных, нет никаких оснований для ее создания.
companion object {}
- Внутри объекта
companion
объявите частный нулевый экземплярINSTANCE
для базы данных и инициализируйте его вnull
. ПеременнаяINSTANCE
будет соблюдать ссылку на базу данных, как только кто -то будет создан. Это помогает вам избежать многократного открытия соединений с базой данных, что дорого.
Аннотировать INSTANCE
с @Volatile
. Значение летучей переменной никогда не будет кэшировано, и все записи и чтения будут выполнены в основной памяти и обратно. Это помогает убедиться, что значение INSTANCE
всегда актуально и одинаково для всех потоков выполнения. Это означает, что изменения, внесенные одним потоком в INSTANCE
, немедленно видны всем другим потокам, и вы не получаете ситуации, когда, скажем, по два потока, каждый из которых обновляет одну и ту же сущность в кэше, что создало бы проблему.
@Volatile
private var INSTANCE: SleepDatabase? = null
-
INSTANCE
ниже, все еще внутри объектаcompanion
, определите методgetInstance()
с параметромContext
, который потребуется застройщику базы данных. Верните типSleepDatabase
. Вы увидите ошибку, потому чтоgetInstance()
еще ничего не возвращает.
fun getInstance(context: Context): SleepDatabase {}
- Inside
getInstance()
, добавьтеsynchronized{}
блок. Пропуститеthis
, чтобы вы могли получить доступ к контексту.
Несколько потоков могут потенциально запрашивать экземпляр базы данных одновременно, что приводит к двум базам данных вместо одной. Эта проблема вряд ли произойдет в этом приложении, но это возможно для более сложного приложения. Обертывание кода, чтобы получить базу данных вsynchronized
означает, что только один поток выполнения за раз может ввести этот блок кода, что гарантирует, что база данных инициализируется только один раз.
synchronized(this) {}
- Внутри синхронизированного блока скопируйте текущее значение
INSTANCE
вinstance
локальной переменной. Это может воспользоваться Smart Cast , который доступен только для локальных переменных.
var instance = INSTANCE
- Внутри
synchronized
блокаreturn instance
в концеsynchronized
блока. Игнорировать ошибку несоответствия типа возврата; Вы никогда не вернете NULL, как только закончите.
return instance
- Выше оператора
return
добавьте операторif
, чтобы проверить, является лиinstance
нулю, то есть, базы данных пока нет.
if (instance == null) {}
- Если
instance
null
, используйте строитель базы данных, чтобы получить базу данных. В теле из оператораif
вызовитеRoom.databaseBuilder
и предоставьте контекст, в котором вы передали, класс базы данных и имя для базы данных,sleep_history_database
. Чтобы удалить ошибку, вам придется добавить стратегию миграции иbuild()
в следующих шагах.
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database")
- Добавьте необходимую стратегию миграции в строитель. Использовать
.fallbackToDestructiveMigration()
.
Обычно вам нужно предоставить миграционный объект с стратегией миграции, когда схема меняется. Миграционный объект - это объект, который определяет, как вы принимаете все строки со старой схемой и конвертируют их в строки в новой схеме, так что данные не теряются. Миграция выходит за рамки этого коделаба. Простое решение - уничтожить и восстановить базу данных, что означает, что данные теряются.
.fallbackToDestructiveMigration()
- Наконец, позвоните
.build()
.
.build()
- Назначить
INSTANCE = instance
как окончательный шаг внутри оператораif
.
INSTANCE = instance
- Ваш окончательный код должен выглядеть так:
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {
abstract val sleepDatabaseDao: SleepDatabaseDao
companion object {
@Volatile
private var INSTANCE: SleepDatabase? = null
fun getInstance(context: Context): SleepDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}
- Создайте и запустите свой код.
Теперь у вас есть все строительные блоки для работы с базой данных вашей Room
. Этот код компилирует и работает, но вы не можете сказать, действительно ли он работает. Итак, это хорошее время, чтобы добавить некоторые основные тесты.
Шаг 2: Проверьте SleepDatabase
На этом этапе вы запускаете предоставленные тесты, чтобы убедиться, что ваша база данных работает. Это помогает гарантировать, что база данных работает, прежде чем вы нарастаете на нее. Предоставленные тесты являются основными. Для производственного приложения вы будете выполнять все функции и запросы во всех DAO.
Приложение стартера содержит папку AndroidTest . Эта папка AndroidTest содержит модульные тесты, которые включают в себя приборы Android, что является причудливым способом сказать, что тесты нуждаются в платформе Android, поэтому вам необходимо запустить тесты на физическом или виртуальном устройстве. Конечно, вы также можете создавать и запустить чистые модульные тесты, которые не включают в себя платформу Android.
- В Android Studio, в папке AndroidTest , откройте файл SleepDataBasetest .
- Чтобы расстроить код, выберите все комментарии и нажмите сочетание
Cmd+/
илиControl+/
клавиатуры. - Взгляните на файл.
Вот быстрый проход кода тестирования, потому что это еще один код, который вы можете повторно использовать:
-
SleepDabaseTest
- это тестовый класс . - Аннотация
@RunWith
идентифицирует тестовый бегун, который является программой, которая устанавливает и выполняет тесты. - Во время настройки функция, аннотированная с
@Before
, выполняется, и создается в памятиSleepDatabase
сSleepDatabaseDao
. «В памяти» означает, что эта база данных не сохраняется в файловой системе и будет удалена после выполнения тестов. - Также при создании базы данных в памяти код вызывает другой метод, специфичный для теста,
allowMainThreadQueries
. По умолчанию вы получаете ошибку, если попытаетесь запустить запросы в главном потоке. Этот метод позволяет запускать тесты в основном потоке, что вы должны делать только во время тестирования. - В методе испытания, аннотированным с
@Test
, вы создаете, вставляете и получаетеSleepNight
, и утверждаете, что они одинаковы. Если что -то пойдет не так, бросьте исключение. В реальном тесте у вас будет несколько@Test
методы - Когда тестирование выполняется, функция, аннотированная с помощью
@After
выполняется для закрытия базы данных.
- Щелкните правой кнопкой мыши тестовый файл на панели проекта и выберите «SleepDataBasetest» .
- После выполнения тестов убедитесь на панели SleepDataBasetest , что прошли все тесты.
Поскольку все тесты прошли, теперь вы знаете несколько вещей:
- База данных создается правильно.
- Вы можете вставить
SleepNight
в базу данных. - Вы можете вернуться в
SleepNight
. -
SleepNight
имеет правильное значение для качества.
Android Studio Project: TrackmysleepQuality и
При тестировании базы данных вам необходимо использовать все методы, определенные в DAO. Чтобы завершить тестирование , добавить и выполнить тесты, чтобы использовать другие методы DAO.
- Определите свои таблицы как классы данных, аннотированные с помощью
@Entity
. Определите свойства, аннотированные с@ColumnInfo
как столбцы в таблицах. - Определите объект доступа данных (DAO) как интерфейс, аннотированный с
@Dao
. DAO Карты Kotlin функционируют на запросы базы данных. - Используйте аннотации, чтобы определить функции
@Insert
,@Delete
и@Update
. - Используйте аннотацию
@Query
со строкой запроса SQLite в качестве параметра для любых других запросов. - Создайте абстрактный класс, который имеет функцию
getInstance()
, которая возвращает базу данных. - Используйте инструментальные тесты, чтобы проверить, что ваша база данных и DAO работают, как и ожидалось. Вы можете использовать предоставленные тесты в качестве шаблона.
Курс Udacity:
Документация разработчика Android:
-
RoomDatabase
-
Database
(аннотации) - Вы можете использовать необработанные запросы в
Room
-
Roomdatabase.Builder
- Тестирование обучения
-
SQLiteDatabase
Class -
Dao
- Библиотека персистентности
Room
Другая документация и статьи:
В этом разделе перечислены возможные домашние задания для студентов, которые работают через этот Codelab в рамках курса, во главе с инструктором. Инструктор должен сделать следующее:
- Назначьте домашнее задание, если это необходимо.
- Сообщите студентам, как отправлять домашние задания.
- Оценка домашних заданий.
Преподаватели могут использовать эти предложения столько, сколько они хотят, и должны свободно назначать любую другую домашнюю работу, которая, по их мнению, является подходящей.
Если вы работаете над этим CodeLab самостоятельно, не стесняйтесь использовать эти домашние задания, чтобы проверить свои знания.
Ответьте на эти вопросы
Вопрос 1
Как вы указываете, что класс представляет собой объект для хранения в базе данных Room
?
- Сделайте класс расширение
DatabaseEntity
. - Анотировать класс
@Entity
. - Аннотируйте класс с
@Database
. - Сделайте класс расширить
RoomEntity
, а также аннотировать класс с помощью@Room
.
Вопрос 2
DAO (объект доступа к данным) - это интерфейс, который Room
использует для картирования функций Kotlin с запросами базы данных.
Как вы указываете, что интерфейс представляет собой DAO для базы данных Room
?
- Сделайте интерфейс расширить
RoomDAO
. - Сделайте интерфейс Extend
EntityDao
, затем реализуйте методDaoConnection()
. - Аннотируйте интерфейс с
@Dao
. - Аннотируйте интерфейс с
@RoomConnection
.
Вопрос 3
Какие из следующих утверждений верны в базу данных Room
? Выберите все, что применимо.
- Вы можете определить таблицы для базы данных
Room
как аннотированные классы данных. - Если вы вернете
LiveData
из запроса,Room
будет держатьLiveData
в обновленной для вас, если изменитсяLiveData
. - Каждая база данных
Room
должна иметь один, и только один, дао. - Чтобы идентифицировать класс в качестве базы данных
Room
, сделайте его подклассомRoomDatabase
и аннотируйте его@Database
.
Вопрос 4
Какие из следующих аннотаций вы можете использовать в своем интерфейсе @Dao
? Выберите все, что применимо.
-
@Get
-
@Update
-
@Insert
-
@Query
Вопрос 5
Как вы можете проверить, что ваша база данных работает? Выберите все, что применимо.
- Напишите инструментальные тесты.
- Продолжайте писать и запустить приложение, пока оно не отобразит данные.
- Замените вызовы на методы в интерфейсе DAO на вызовы эквивалентных методов в классе
Entity
. - Запустите функцию
verifyDatabase()
предоставленную библиотекойRoom
.
Начните на следующий урок:
Ссылки на другие коделабы в этом курсе см. Взъективную целевую страницу CodeLabs Foundals Android Kotlin .