- Урок 5. Room. Основы
- Подключение к проекту
- Entity
- Database
- Практика
- UI поток
- Переход на Room
- Room Database Android Example [Beginners]
- Why use Room Database?
- What is the difference between room and sqlite database ?
- There Are Basically 3 Major Components In Room.
- 1. @Entity
- 2. @Dao — Data Access Object
- 3. @Database
- Step 1 — Add dependencies
- Step 2: Create a Model Class
- Step 3 — Create DAO (Data Access Objects)
- Type Converters
- Step 4 — Create the database
- Step 5 — CRUD operation on Room Database
- Conclusion
- Русские Блоги
- Android Room Официальное руководство
- Краткое введение
- Библиотека импорта
- Используйте Room для сохранения локальных данных в базе данных
- Определение данных с использованием сущностей Room
- Использовать первичный ключ
- Аннотация аннотации и уникальность
- Определить отношения между объектами
- Создать вложенные объекты
- Доступ к данным с помощью комнатных DAO
- Определить метод запроса
- Вставить
- обновление
- Удалить
- Информационный запрос
- Простой запрос
- Передача параметров в запрос
- Возвращает подмножество столбцов
- Передача набора параметров
- Наблюдаемый запрос
- RXJava Реактивный запрос
- Прямой доступ к курсору
- Многостоловый запрос
- Миграция базы данных комнат
- Тестовая миграция
- Экспортные схемы
- Тестовая база данных
- Тест Android устройства
- Хост тест
- Справочный комплекс данных с комнатой
- Использование преобразователей типов
- Понять, почему Room не допускает ссылки на объекты
Урок 5. Room. Основы
Библиотека Room предоставляет нам удобную обертку для работы с базой данных SQLite. В этом уроке рассмотрим основы. Как подключить к проекту. Как получать, вставлять, обновлять и удалять данные.
Полный список уроков курса:
Подключение к проекту
В build.gradle файл проекта добавьте репозитарий google()
В build.gradle файле модуля добавьте dependencies:
Если у вас студия ниже 3.0 и старые версии Gradle и Android Plugin, то подключение будет выглядеть так:
Room имеет три основных компонента: Entity, Dao и Database. Рассмотрим их на небольшом примере, в котором будем создавать базу данных для хранения данных по сотрудникам (англ. — employee).
При работе с Room нам необходимо будет писать SQL запросы. Если вы не знакомы с ними, то имеет смысл прочесть хотя бы основы.
Entity
Аннотацией Entity нам необходимо пометить объект, который мы хотим хранить в базе данных. Для этого создаем класс Employee, который будет представлять собой данные сотрудника: id, имя, зарплата:
Класс помечается аннотацией Entity. Объекты класса Employee будут использоваться при работе с базой данных. Например, мы будем получать их от базы при запросах данных и отправлять их в базу при вставке данных.
Этот же класс Employee будет использован для создания таблицы в базе. В качестве имени таблицы будет использовано имя класса. А поля таблицы будут созданы в соответствии с полями класса.
Аннотацией PrimaryKey мы помечаем поле, которое будет ключом в таблице.
В следующих уроках мы рассмотрим возможности Entity более подробно.
В объекте Dao мы будем описывать методы для работы с базой данных. Нам нужны будут методы для получения списка сотрудников и для добавления/изменения/удаления сотрудников.
Описываем их в интерфейсе с аннотацией Dao.
Методы getAll и getById позволяют получить полный список сотрудников или конкретного сотрудника по id. В аннотации Query нам необходимо прописать соответствующие SQL-запросы, которые будут использованы для получения данных.
Обратите внимание, что в качестве имени таблицы мы используем employee. Напомню, что имя таблицы равно имени Entity класса, т.е. Employee, но в SQLite не важен регистр в именах таблиц, поэтому можем писать employee.
Для вставки/обновления/удаления используются методы insert/update/delete с соответствующими аннотациями. Тут никакие запросы указывать не нужно. Названия методов могут быть любыми. Главное — аннотации.
В следующих уроках мы рассмотрим возможности Dao и его аннотаций более подробно.
Database
Аннотацией Database помечаем основной класс по работе с базой данных. Этот класс должен быть абстрактным и наследовать RoomDatabase.
В параметрах аннотации Database указываем, какие Entity будут использоваться, и версию базы. Для каждого Entity класса из списка entities будет создана таблица.
В Database классе необходимо описать абстрактные методы для получения Dao объектов, которые вам понадобятся.
Практика
Все необходимые для работы объекты созданы. Давайте посмотрим, как использовать их для работы с базой данных.
Database объект — это стартовая точка. Его создание выглядит так:
Используем Application Context, а также указываем AppDatabase класс и имя файла для базы.
Учитывайте, что при вызове этого кода Room каждый раз будет создавать новый экземпляр AppDatabase. Эти экземпляры очень тяжелые и рекомендуется использовать один экземпляр для всех ваших операций. Поэтому вам необходимо позаботиться о синглтоне для этого объекта. Это можно сделать с помощью Dagger, например.
Если вы не используете Dagger (или другой DI механизм), то можно использовать Application класс для создания и хранения AppDatabase:
Не забудьте добавить App класс в манифест
В коде получение базы будет выглядеть так:
Из Database объекта получаем Dao.
Теперь мы можем работать с Employee объектами. Но эти операции должны выполняться не в UI потоке. Иначе мы получим Exception.
Добавление нового сотрудника в базу будет выглядеть так:
Метод getAll вернет нам всех сотрудников в List
Получение сотрудника по id:
Обновление данных по сотруднику.
Room будет искать в таблице запись по ключевому полю, т.е. по id. Если в объекте employee не заполнено поле id, то по умолчанию в нашем примере оно будет равно нулю и Room просто не найдет такого сотрудника (если, конечно, у вас нет записи с >
Аналогично обновлению, Room будет искать запись по ключевому полю, т.е. по id
Давайте для примера добавим еще один тип объекта — Car.
Описываем Entity объект
Теперь Dao для работы с Car объектом
Будем считать, что нам надо только читать все записи, добавлять новые и удалять старые.
В Database необходимо добавить Car в список entities и новый метод для получения CarDao
Т.к. мы добавили новую таблицу, изменилась структура базы данных. И нам необходимо поднять версию базы данных до 2. Но об этом мы подробно поговорим в Уроке 12. А пока можно оставить версию равной 1, удалить старую версию приложения и поставить новую.
UI поток
Повторюсь, операции по работе с базой данных — синхронные, и должны выполняться не в UI потоке.
В случае с Query операциями мы можем сделать их асинхронными используя LiveData или RxJava. Об этом еще поговорим в следующих уроках.
В случае insert/update/delete вы можете обернуть эти методы в асинхронный RxJava. В моем блоге есть статья на эту тему.
Также, вы можете использовать allowMainThreadQueries в билдере создания AppDatabase
В этом случае вы не будете получать Exception при работе в UI потоке. Но вы должны понимать, что это плохая практика, и может добавить ощутимых тормозов вашему приложению.
Переход на Room
Если вы надумали с SQLite мигрировать на Room, то вот пара полезных ссылок по этой теме:
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник
Room Database Android Example [Beginners]
Room Database is a part of the Android Architecture components which provides an abstraction layer over SQLite which allows for more robust database access while still providing the full power of SQLite.
Room is a persistence library, part of the Android Jetpack
Why use Room Database?
- Compile-time verification of SQL queries. each @Query and @Entity is checked at the compile time.
- Using Annotations to reduce the boilerplate code.
- Easily integrated with other Architecture components like LiveData, RxJava.
What is the difference between room and sqlite database ?
- In case of SQLite, There is no compile time verification of raw SQLite queries. But in Room there is SQL validation at compile time.
- As your schema changes, you need to update the affected SQL queries manually. Room solves this problem.
- You need to use lots of boilerplate code to convert between SQL queries and Java data objects. But, Room maps our database objects to Java Object without boilerplate code.
- Room is built to work with LiveData and RxJava for data observation, while SQLite does not.
Room architecture looks like the following:
There Are Basically 3 Major Components In Room.
1. @Entity
Entity Representation of table and columns become very easy. you have to annotate “ @Entity ” to a class and name of the class becomes table name and, data members becomes the name of the columns. “ @Entity” class represent an entity in a table.
2. @Dao — Data Access Object
An Interface where we put all our SQL queries. We don’t require to write whole queries now; we need to make a method and annotate with specific annotations like
@ Insert — Used to insert record into Room database.
@Delete — Used to delete record from Room database.
@Update — Used to update record in Room Database.
@ Query — Used to enter the Query like (SELECT FROM*)”
3. @Database
This is an abstract class that extends RoomDatabase, this is where you define the entities (tables)and the version number of your database. It contains the database holder and serves as the main access point for the underlying connection.
Done with explanation. Lets start the implementation part.
am going to create a sample app for user management using the room database in kotlin. In the app, I have added functionalities to insert, delete, update and list all the users.
Step 1 — Add dependencies
First, We need to add dependencies for room database in our build.gradle file.
Step 2: Create a Model Class
Room creates a table for each class annotated with @Entity.
- Annotate the class with @Entity and use the tableNameproperty to set the name of the table.
- Set the primary key by adding the “@primaryKey” annotation to the correct fields — in our case, this is the ID of the User.
- Set the name of the columns for the class fields using the @ColumnInfo(name = “column_name”) annotation. Feel free to skip this step if your fields already have the correct column name.
- If multiple constructors are suitable, add the @Ignore annotation to tell Room which should be used and which not.
Step 3 — Create DAO (Data Access Objects)
DAOs are responsible for defining the methods that access the database.
Here we just define basic SQL database functionality like inserting and deleting entries. You can see that the @Query annotation is used to annotate functions which are using queries.
You can also use parameters in your queries using : parametername .
Type Converters
Type Converters are used when we declare a property which Room and SQL don’t know how to serialize. Let’s see an example of how to serialize List data type.
Step 4 — Create the database
Now, Everything is ready to create Database. We can create Room Database by extend the RoomDatabase.
Things to notice here:
- This is an abstract class that has to extend from RoomDatabase.
- It has to be annotated with @Database, it receives a list of entities with all the classes that compose the database (all these classes have to be annotated with @Entity). We also have to provide a database version.
- We have to declare an abstract function for each of the entities included in the @Database annotation, this function has to return the correspondentDAO (A class annotated with @Dao).
- Finally, we declare a companion object to get static access to the method getAppDataBase which gives us a singleton instance of the database.
Step 5 — CRUD operation on Room Database
Now the room database is ready for the CRUD operation.
If you try running the above code with the created database above, your app will crash as the operation performed is on the main thread. By default, Room keeps a check of that and doesn’t allow operations on the main thread as it can makes your UI Not responding.
You can avoid that by using AsyncTask or Handler or Rxjava with IO schedulers or any other options which puts the operation on any other thread.
There is one more option, which allows you to do the operation on the main thread. You can use the same for testing but should avoid. To do that you can add allowMainThreadQueries() on the builder.
Result of my room database android example.
Also, You can download the example in github.
Conclusion
Thanks for reading.
Please try room database in android with different query to practice. And let me know your feedback in comments.
Give a clap 👏 if you like it.
Источник
Русские Блоги
Android Room Официальное руководство
Официальный перевод документов
Краткое введение
RoomПостоянная библиотека обеспечивает уровень абстракции SQLite, позволяющий получить более надежный доступ к базе данных и повысить ее производительность.
Эта библиотека помогает вам создать кэш данных приложения на устройстве, на котором выполняется приложение. Этот кеш является единственным истинным источником вашего приложения, позволяя пользователям просматривать непротиворечивую копию ключевой информации в приложении, независимо от того, имеет ли пользователь подключение к Интернету.
Библиотека импорта
Используйте Room для сохранения локальных данных в базе данных
Room обеспечивает уровень абстракции в SQLite, чтобы обеспечить беспрепятственный доступ к базе данных при одновременном использовании возможностей SQLite.
Приложения, которые обрабатывают сложные структурированные данные, могут значительно выиграть от сохранения локальных данных. Наиболее распространенным вариантом использования является кэширование связанных данных. Таким образом, когда устройство не может получить доступ к сети, пользователи могут просматривать содержимое в автономном режиме. После того, как устройство возвращается в оперативный режим, любые изменения содержимого, инициированные пользователем, синхронизируются с сервером.
Поскольку Room отвечает за эти проблемы, мы настоятельно рекомендуем использовать Room вместо SQLite. Однако, если вы более привыкли использовать SQLite API напрямую, используйтеSQLite читать сохранить данные。
В номере 3 основных компонента:
DatabaseСодержит держатель базы данных и служит основной точкой доступа для основного соединения с постоянными реляционными данными приложения.
Использовать@DatabaseАннотированные классы должны удовлетворять следующим условиям:
Это наследствоRoomDatabaseАбстрактный класс.
Включить в комментарий список объектов, связанных с базой данных.
Во время выполнения вы можете позвонитьRoom.databaseBuilder()илиRoom.inMemoryDatabaseBuilder()Получить экземпляр базы данных.
Entity: Представляет таблицу в базе данных.
DAO: Содержит методы для доступа к базе данных.
Эти компоненты и их связь с остальной частью приложения показаны на рисунке 1:
Рисунок 1. Схема архитектуры помещения
Следующий фрагмент кода иллюстрирует конфигурацию базы данных с сущностью и DAO:
После создания вышеуказанного файла используйте следующий код, чтобы получить экземпляр созданной базы данных:
Примечание: перед созданием экземпляраAppDatabaseОбъекты, вы должны следовать шаблону проектирования Singleton, потому что каждыйRoomdatabaseЭкземпляры довольно дороги, и вам редко требуется доступ к нескольким экземплярам.
Чтобы испытать номер, попробуйтеAndroid Room with a ViewиПостоянство Android codelabs. Чтобы просмотреть примеры кода комнаты, см.Android Architecture Components samples。
Определение данных с использованием сущностей Room
По умолчанию Room создает столбец для каждого поля, определенного в объекте. Если у сущности есть поля, которые вы не хотите сохранять, вы можете использовать@IgnoreЧтобы комментировать их. Должен пройти через класс базы данныхentitiesМассив ссылается на класс сущности.
Следующий фрагмент кода показывает, как определить сущность:
Чтобы сохранить поле, Комната должна иметь шанс войти в него. Вы можете выставить поле или предоставить метод получения и установки для него. Если вы используете методы получения и установки, имейте в виду, что они основаны на соглашениях JavaBeans в Room.
Примечание: сущности могут иметь пустые конструкторы (если соответствующиеDAOКласс может обращаться к каждому постоянному полю) или к конструктору, параметры которого содержат тип и имя, соответствующие полям в сущности. Комната может также использовать весь конструктор или его часть, например конструктор, который получает только некоторые поля.
Использовать первичный ключ
Каждый объект должен определить как минимум 1 поле в качестве первичного ключа. Даже если есть только 1 поле, вам все равно нужно использовать@PrimaryKeyАннотации полей. Кроме того, если вы хотите, чтобы Room автоматически назначал идентификаторы сущностям, вы можете установить @ PrimaryKey’sautoGenerateНедвижимость. Если у объекта есть составной первичный ключ, вы можете использовать@EntityАннотированное свойство primaryKeys показано в следующем фрагменте кода:
By default, Room uses the class name as the database table name. If you want the table to have a different name, set the tableName property of the @Entity annotation, as shown in the following code snippet:
По умолчанию Room использует имя класса в качестве имени таблицы базы данных. Если вы хотите, чтобы таблица имела другое имя, установите аннотацию @EntitytableNameАтрибуты, как показано в следующем фрагменте кода:
Обратите внимание: Имена таблиц в SQLite не чувствительны к регистру.
Подобно свойству tableName, Room использует имя поля в качестве имени столбца в базе данных. Если вы хотите, чтобы столбцы имели разные имена, измените@ColumnInfoВ поле добавляется аннотация, как показано в следующем фрагменте кода:
Аннотация аннотации и уникальность
В зависимости от способа доступа к данным вам может потребоваться проиндексировать определенные поля в базе данных, чтобы ускорить запросы. Добавить к сущностииндексПожалуйста@EntityКомментарий содержит атрибут индекса, в котором перечислены имена столбцов, которые должны быть включены в индекс или составной индекс. Следующий фрагмент кода демонстрирует этот процесс аннотации:
Иногда определенные поля или группы полей в базе данных должны бытьуникальныйA. Может быть изменено@IndexУникальный атрибут аннотации имеет значение true, чтобы применить этот уникальный атрибут. В следующем примере кода запрещается, чтобы таблица содержала две строки, содержащие одинаковый набор значений для столбцов firstName и lastName:
Определить отношения между объектами
Поскольку SQLite — это реляционная база данных, вы можете указать отношения между объектами. Хотя большинство библиотек объектно-реляционного отображения позволяют объектным объектам ссылаться друг на друга, Room явно запрещает это. Чтобы понять техническое обоснование этого решения, пожалуйста, поймитеПочему Room не допускает ссылки на объекты。
Даже если вы не можете использовать прямые отношения, Room по-прежнему позволяет определять ограничения внешнего ключа между объектами.
Например, если есть другая сущность с именем Book, вы можете использовать@ForeignKey Аннотации определяют их отношение к пользовательским объектам, как показано в следующем фрагменте кода:
Внешние ключи очень мощные, потому что они позволяют вам указать, что происходит при обновлении ссылочной сущности. Например, если вы включите в аннотацию @ForeignKeyonDelete = CASCADE, Вы можете указать SQLite удалить все книги для пользователя, если удаляется соответствующий экземпляр пользователя.
Обратите внимание: Обработка SQLite@Insert( onconflict=REPLACE)Как набор операций REMOVE и REPLACE вместо одной операции обновления. Этот метод замены конфликтующих значений может повлиять на ограничения внешнего ключа. Для более подробной информации, пожалуйста, смотритеДокументация по SQLiteУсловия использования ON_CONFLICT.
Создать вложенные объекты
Иногда, даже если объект содержит несколько полей, вы хотите представить сущность или простой Java-объект (POJO) как единое целое в логике базы данных. В этих случаях вы можете использовать@EmbeddedАннотации для представления объектов, которые должны быть разбиты на подполя в таблице. Встроенные поля могут быть запрошены, как и любой другой столбец.
Например, наш пользовательский класс может включать в себя поле адреса типа, которое представляет собой комбинацию полей с именами «улица», «город», «статус» и «почтовый индекс». Чтобы хранить объединенные столбцы отдельно в таблице, используйте поле аннотированного адреса @Embedded в пользовательском классе, как показано в следующем фрагменте кода:
Таблица, представляющая объект пользователя, содержит столбцы со следующими именами: id, firstName, улица, штат, город и почтовый индекс.
Обратите внимание: Встроенные поля могут также включать другие встроенные поля.
Если у сущности есть несколько встроенных полей одного типа, это можно сделать, установивprefixАтрибуты для сохранения каждого столбца уникальным. Предоставленное значение затем добавляется в начало каждого имени столбца во встроенном объекте.
Доступ к данным с помощью комнатных DAO
Для доступа к данным вашего приложения используйте «Библиотеку постоянства помещения». Вы можете использовать объекты доступа к данным или DAO. Этот набор объектов DAO составляет основной компонент Помещения, поскольку каждый DAO содержит абстрактные методы для доступа к базе данных приложения.
Используя классы DAO для доступа к базе данных вместо построителя запросов или прямого запроса, вы можете разделить различные компоненты архитектуры базы данных. Кроме того, DAO позволяют легко имитировать доступ к базе данных при тестировании приложения.
Обратите внимание: Перед добавлением класса DAO в приложение,Добавлена библиотека компонентов архитектурыПерейдите в build.gradle приложения.
DAO может быть интерфейсом или абстрактным классом. Если это абстрактный класс, он может иметь конструктор, который помещаетRoomDatabaseКак единственный параметр. Room создает каждую реализацию DAO во время компиляции.
Обратите внимание: Если не вызвано на строителяallowMainThreadQueries()В противном случае Room не поддерживает доступ к базе данных в главном потоке, поскольку он может заблокировать пользовательский интерфейс на длительное время. Вернуться кLiveDataилиFlowableАсинхронные запросы для экземпляров исключаются из этого правила, поскольку при необходимости они выполняют запросы в фоновом потоке.
Определить метод запроса
Существует несколько методов запроса, которые можно представить с помощью класса DAO. Этот документ включает несколько общих примеров.
Вставить
Когда вы создаете метод DAO и используете@InsertПри аннотировании Room генерирует реализацию, которая вставляет все параметры в базу данных за одну транзакцию.
Следующий фрагмент кода показывает несколько примеров запросов:
Если метод @Insert получает только 1 параметр, он может вернуть значение Long, которое является новым rowId вставленного элемента. Если аргумент является массивом или коллекцией, он должен возвращать значение типа long [] или List.
Для получения дополнительной информации см. Справочную документацию, аннотированную @Insert, иSQLite documentation for rowid tables。
обновление
UpdateМетоды используются в базе данных для изменения полей набора сущностей. Он использует первичный ключ каждой сущности для соответствия запросу.
Следующий фрагмент кода показывает, как определить этот метод:
Хотя обычно это не требуется, вы можете заставить этот метод возвращать значение типа int, чтобы указать количество строк, обновляемых в базе данных.
Удалить
DeleteЭтот метод используется для удаления серии объектов с заданным параметром из базы данных и использует первичный ключ для сопоставления с соответствующей строкой в базе данных.
Следующий фрагмент кода показывает, как определить этот метод:
Хотя обычно это не требуется, вы можете использовать этот метод для возврата значения int, чтобы указать количество строк, удаленных из базы данных.
Информационный запрос
@QueryОсновная аннотация, используемая в классе DAO. Это позволяет выполнять операции чтения / записи в базе данных. Каждый метод @Query проверяется во время компиляции, поэтому, если возникает проблема с запросом, вместо сбоя во время выполнения возникает ошибка компиляции.
Room также проверяет возвращаемое значение запроса, чтобы, если имена полей в возвращаемом объекте не совпадали с именами соответствующих столбцов в ответе на запрос, Room напомнит вам одним из двух способов:
Предупреждать, если совпадают только некоторые имена полей.
Если имя поля не совпадает, возникает ошибка.
Простой запрос
Это очень простой запрос, который загружает всех пользователей. Во время компиляции Room знает, что она запрашивает все столбцы в пользовательской таблице. Если запрос содержит синтаксическую ошибку или если пользовательская таблица не существует в базе данных, Room отобразит соответствующую ошибку при компиляции приложения.
Передача параметров в запрос
В большинстве случаев вам необходимо передать параметры в запрос для выполнения операций фильтрации, например, показывать только пользователей старше определенного возраста. Для этого используйте параметры метода в аннотации Room, как показано в следующем фрагменте кода:
Когда этот запрос обрабатывается во время компиляции, параметры привязки Room соответствуют параметрам метода minAge. Комната выполняет сопоставление, используя имя параметра. В случае несоответствия возникает ошибка при компиляции приложения.
Вы также можете передать несколько параметров или ссылаться на них несколько раз в запросе, как показано в следующем фрагменте кода:
Возвращает подмножество столбцов
В большинстве случаев вам нужно всего лишь получить несколько полей сущности. Например, ваш пользовательский интерфейс может отображать только имя и фамилию пользователя, а не все детали пользователя. Выбирая только столбцы, которые отображаются в пользовательском интерфейсе приложения, вы можете сохранить ценные ресурсы и быстрее выполнить запрос.
Пока столбцы результата могут быть сопоставлены с возвращаемыми объектами, вы можете вернуть любой объект на основе Java из вашего запроса. Например, вы можете создать следующий общий объект на основе Java (POJO), чтобы получить имя и фамилию пользователя:
Теперь вы можете использовать этот POJO в вашем методе запроса:
Room знает, что запрос возвращает значения для столбцов first_name и last_name, и эти значения можно сопоставить с полями в классе NameTuple. Поэтому Room может генерировать соответствующий код. Если запрос возвращает слишком много столбцов или один столбец не существует в классе NameTuple, в Room отобразится предупреждение.
Примечание: эти POJO также могут быть использованы@EmbeddedПримечания.
Передача набора параметров
В некоторых запросах может потребоваться передать переменное количество параметров, где точное количество параметров неизвестно до времени выполнения. Например, вы можете получить информацию обо всех пользователях из подмножества региона. Комната понимает, когда параметр представляет коллекцию, и автоматически расширяет ее во время выполнения, основываясь на количестве предоставленных параметров.
Наблюдаемый запрос
При выполнении запроса вы часто хотите, чтобы пользовательский интерфейс вашего приложения автоматически обновлялся при изменении данных. Для этого используйте типы в описании метода запросаLiveDataВозвращаемое значение Когда база данных обновляется, Room генерирует весь необходимый код для обновления LiveData.
Обратите вниманиеВ версии 1 Room решает, обновлять ли экземпляр LiveData на основе списка запросов.
RXJava Реактивный запрос
Room также может возвращать RXJava2 из заданных вами запросовPublisherиFlowableДвижущийся объект. Чтобы использовать эту функцию, добавьте библиотеку android.arch.persistence.room:rxjava2 в зависимости gradle. Затем вы можете вернуть объект типа, определенный в RXJava2, как показано в следующем фрагменте кода:
Для получения дополнительной информации см. Google Developers.Комната и RXJavaСтатья.
Прямой доступ к курсору
Если логика вашего приложения требует прямого доступа к возвращенным строкам, вы можете вернуть объект Cursor из запроса, как показано в следующем фрагменте кода:
Обратите вниманиеИспользование API-интерфейса Cursor очень разочаровывает, поскольку не может гарантировать, существует ли строка или какие значения содержит строка. Используйте эту функцию, только если у вас уже есть код, который ожидает Cursor, и код нелегко реорганизовать.
Многостоловый запрос
Некоторые запросы могут требовать доступа к нескольким таблицам для расчета результатов. Room позволяет вам написать любой запрос, поэтому вы также можете объединить запросы на несколько таблиц. Кроме того, если возвращается наблюдаемый тип данных, такой какFlowableилиLiveData, Room будет контролировать все таблицы, указанные в запросе, чтобы обновить данные.
В следующем фрагменте кода показано, как выполнить запрос из нескольких таблиц. Пример кода содержит информацию об ассоциации между пользователями, книгами и таблицами данных ссуды:
POJO также могут быть возвращены из этих запросов. Например, вы можете написать запрос, который загружает имена пользователей и их питомцев следующим образом:
Миграция базы данных комнат
Когда вы добавляете и изменяете атрибуты в своем приложении, вам нужно изменить классы сущностей, чтобы отразить эти изменения. Когда пользователи обновляют приложения до последней версии, они не хотят, чтобы они теряли все свои существующие данные, особенно если данные не могут быть восстановлены с удаленного сервера.
“Room persistence library«Библиотеки позволяют писатьMigrationКласс для хранения пользовательских данных. Каждый класс миграции определяет начальную и конечную версию. Во время выполнения Room запускает каждый класс миграции.migrate()Метод, используя правильный порядок для переноса базы данных в более позднюю версию.
Обратите внимание: Если вы не предоставите необходимую миграцию, Room перестроит базу данных, что означает, что вы потеряете все данные в базе данных.
Обратите внимание: Чтобы логика миграции работала, используйте полные запросы вместо ссылок на константы, представляющие запросы.
После завершения процесса миграции Room проверяет схему, чтобы убедиться, что миграция прошла правильно. Если Room находит проблему, она генерирует исключение, содержащее информацию о несоответствии.
Тестовая миграция
Миграция не является тривиальной и не может быть написана правильно и может привести к сбою приложения. Чтобы сохранить стабильность вашего приложения, вы должны предварительно протестировать миграцию. Room предоставляет тестовые компоненты Maven, чтобы помочь с этим процессом тестирования. Однако, чтобы этот компонент работал, вам необходимо экспортировать схему базы данных.
Экспортные схемы
После компиляции Room экспортирует информацию о схемах базы данных в файл JSON. Чтобы экспортировать схему, установите свойство процессора аннотаций room.schemaLocation в файле build.gradle, как показано в следующем фрагменте кода:
Вам следует сохранить экспортированный файл JSON, представляющий историю схемы вашей базы данных, в вашей системе управления версиями, поскольку это позволяет Room создавать более старые версии базы данных для целей тестирования.
Чтобы проверить эти миграции, добавьте зависимость Maven android.arch.persistence.room:testing и добавьте схему в папку ресурсов, как показано в следующем фрагменте кода:
Тестовый пакет предоставляет класс MigrationTestHelper, который может читать эти файлы схемы. Он также реализует интерфейс JUnit4 TestRule, поэтому он может управлять созданной базой данных.
Пример теста миграции приведен в следующем фрагменте:
Тестовая база данных
При использовании библиотеки Room для создания базы данных важно проверить стабильность базы данных приложения и пользовательских данных.
Есть 2 способа проверить базу данных:
На устройстве Android.
На машине разработки хоста (не рекомендуется).
Для конкретной миграции базы данных, см.Миграционный тест。
Обратите внимание: При запуске тестов для вашего приложения Room позволяет создавать фиктивные экземпляры класса DAO. Таким образом, вам не нужно создавать полную базу данных без тестирования самой базы данных. Эта функция возможна, потому что ваши DAO не будут пропускать какие-либо детали базы данных.
Тест Android устройства
Рекомендуемый способ проверки реализации базы данных — написать тест JUnit, работающий на устройстве Android. Поскольку эти тесты не должны создавать действия, они должны выполняться быстрее, чем тесты пользовательского интерфейса.
При настройке теста вы должны создать версию базы данных в памяти, чтобы сделать тест более закрытым, как показано в следующем примере:
Хост тест
Room использует библиотеку поддержки SQLite, которая предоставляет интерфейсы, соответствующие интерфейсам классов платформы Android. Эта поддержка позволяет тестировать запросы к базе данных с помощью специальной реализации библиотеки поддержки.
Обратите внимание: Несмотря на то, что этот параметр позволяет выполнять ваши тесты быстро, это не рекомендуется, поскольку версия SQLite, работающая на вашем устройстве, и пользовательское устройство могут не соответствовать версии на хосте.
Справочный комплекс данных с комнатой
Room обеспечивает возможность преобразования между примитивным и коробочным типами, но не допускает ссылки на объекты между сущностями. Этот документ объясняет, как использовать преобразователи типов и почему Room не поддерживает ссылки на объекты.
Использование преобразователей типов
Иногда приложения должны использовать пользовательские типы данных, значения которых хранятся в одном столбце базы данных. Чтобы добавить эту поддержку в пользовательские типы, вы предоставляетеTypeConverter, Который преобразует пользовательский класс в известный тип, который может быть постоянным.
Например, если мы хотим сохранитьDateПримеры, вы можете написать следующееTypeConverterЧтобы сохранить эквивалентную метку времени UNIX в базе данных:
В предыдущем примере определены две функции, одна из которых преобразует объект Date в объект Long, а другая выполняет обратное преобразование из Long в Date. Поскольку Room уже знает, как сохранять объекты Long, он может использовать этот конвертер для хранения значений типа Date.
Затем добавьте в класс AppDatabase@TypeConvertersКомментарии, поэтому AppDatabase может использовать вас для каждогоentityОпределенные конвертеры и DAO:
Используя эти конвертеры, вы можете использовать свои пользовательские типы в других запросах так же, как и примитивные типы, как показано в следующем фрагменте кода:
Вы также можете добавить@TypeConvertersОграничено различными областями, включая отдельные объекты, методы DAO и DAO. Для получения дополнительной информации см.@TypeConvertersАннотированная справочная документация.
Понять, почему Room не допускает ссылки на объекты
Обратите особое внимание: Комната не допускает ссылки на объекты между классами сущностей. Вместо этого вы должны явно запросить данные, которые нужны вашему приложению.
Отображение из базы данных в соответствующую объектную модель является обычной операцией, которая хорошо работает на стороне сервера. Даже если программа загружает поля при доступе, сервер все равно работает хорошо.
Однако на стороне клиента этот тип отложенной загрузки невозможен, поскольку он обычно выполняется в потоке пользовательского интерфейса, а запрос информации на диске в потоке пользовательского интерфейса может вызвать значительные проблемы с производительностью. Поток пользовательского интерфейса обычно имеет около 16 мс для вычисления и отрисовки обновленного макета действия, поэтому даже если запрос занимает всего 5 мсек, у вашего приложения может все еще не хватить времени для отрисовки фреймов, что приводит к значительной визуальной задержке. Если параллельно выполняется одна транзакция или если на устройстве выполняются другие задачи с интенсивным использованием диска, выполнение запроса может занять больше времени. Однако, если вы не используете отложенную загрузку, ваше приложение получит больше данных, чем нужно, что вызовет проблемы с использованием памяти.
Объектно-реляционное отображение обычно оставляет это решение разработчикам, чтобы они могли делать все, что лучше для их варианта использования приложения. Разработчики часто решают поделиться моделью между приложением и пользовательским интерфейсом. Однако это решение невелико по масштабу, поскольку пользовательский интерфейс меняется со временем, а общая модель создает проблемы, которые разработчики вряд ли могут предсказать и отладить.
Например, рассмотрим пользовательский интерфейс, который загружает список объектов книги, и у каждой книги есть объект автора. Вы могли бы изначально спроектировать свой запрос для использования отложенной загрузки, чтобы использовать метод getAuthor () для возврата автора. Первый вызов getAuthor () запрашивает базу данных. Через некоторое время вы понимаете, что вам нужно показывать имена авторов в пользовательском интерфейсе приложения. Вы можете легко добавить вызовы метода, как показано в следующем фрагменте кода:
Однако это, казалось бы, безобидное изменение вызвало запрос таблицы автора в главном потоке.
Если вы запрашиваете информацию об авторе заранее, трудно изменить способ загрузки данных, если данные больше не нужны. Например, если пользовательскому интерфейсу вашего приложения больше не нужно отображать информацию об авторе, ваше приложение эффективно загружает данные, которые больше не отображаются, тратя драгоценное пространство памяти. Если класс автора ссылается на другую таблицу, например на книгу, эффективность приложения еще больше снижается.
При использовании Room для одновременного обращения к нескольким объектам вам необходимо создать POJO, содержащий каждый объект, а затем написать запрос, который соединяет соответствующие таблицы (запросы к нескольким таблицам, вы должны сначала найти необходимые данные). Эта хорошо структурированная модель в сочетании с мощными возможностями проверки запросов Room позволяет приложениям потреблять меньше ресурсов при загрузке данных, повышая производительность приложений и удобство работы пользователей.
Источник