- 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
- 7 полезных советов для тех, кто использует Room
- 1. Предварительное заполнение базы данных
- 2. Использование возможностей наследования DAO
- 3. Выполнение запросов в транзакциях без шаблонного кода
- 4. Чтение только того, что вам нужно
- 5. Контроль зависимостей между сущностями с внешними ключами
- 6. Упрощение запросов один-ко-многим с помощью @Relation
- 7. Избежание ложных уведомлений observable-запросов
- Room: Хранение данных на Android для всех и каждого
- Использование Room
- Преимущества использования Room
- Самое большое ограничение в Room: взаимосвязи
- Стоит ли использовать Room?
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.
Источник
7 полезных советов для тех, кто использует Room
Room — это уровень абстракции поверх SQLite, который упрощает организацию хранения данных. Если вы ещё мало знакомы с Room, то посмотрите эту вводную статью:
А в этой статье я хотел бы поделиться несколькими советами о том, как максимально эффективно использовать Room.
1. Предварительное заполнение базы данных
Вам нужно добавить данные по умолчанию в вашу базу данных сразу после её создания или в момент первого обращения к ней? Используйте RoomDatabase#Callback. Вызовите метод addCallback при создании вашей базы данных и переопределите либо onCreate, либо onOpen.
onCreate будет вызываться при первом создании базы данных, сразу после создания таблиц. onOpen вызывается при открытии базы данных. Поскольку доступ к DAO возможен только после завершения этих методов, мы создаём новый поток, в котором получаем ссылку на базу данных, затем получаем DAO и вставляем необходимые данные.
Смотрите полный пример здесь.
Примечание: если вы будете использовать подход с ioThread и приложение даст сбой при первом запуске, между созданием базы данных и вставкой, данные никогда не будут вставлены.
2. Использование возможностей наследования DAO
У вас есть несколько таблиц в вашей базе данных и вы копируете одни и те же методы вставки, обновления и удаления? DAO поддерживают наследование, поэтому создайте класс BaseDao и определите там ваши общие методы @Insert , @Update и @Delete . Пусть каждый DAO расширит BaseDao и добавит методы, специфичные для каждого из них.
DAO должны быть интерфейсами или абстрактными классами, потому что Room генерирует их реализации во время компиляции, включая методы из BaseDao .
3. Выполнение запросов в транзакциях без шаблонного кода
Аннотирование метода с помощью @Transaction гарантирует, что все операции базы данных, которые вы выполняете в этом методе, будут выполняться внутри одной транзакции. Транзакция не будет выполнена, если в теле метода возникнет исключение.
Возможно, вы захотите использовать аннотацию @Transaction для методов @Query , которые используют оператор select в случаях:
- Когда результат запроса довольно большой. Делая запрос одной транзакцией, вы гарантируете, что если результат запроса не поместится в одной «порции» курсора, то он не будет повреждён из-за изменений в базе данных между перестановками курсора.
- Когда результатом запроса является POJO с полями @Relation . Каждое поле является запросом само по себе, поэтому запуск их в одной транзакции гарантирует согласованные результаты между запросами.
Методы @Delete , @Update и @Insert , имеющие несколько параметров, автоматически запускаются внутри транзакции.
4. Чтение только того, что вам нужно
Когда вы делаете запрос к базе данных, используете ли вы все поля, которые получаете в ответе? Позаботьтесь об объёме памяти, используемой вашим приложением, и загрузите только те поля, которые вы в конечном итоге будете использовать. Это также увеличит скорость ваших запросов за счёт снижения затрат на ввод-вывод. Room сделает сопоставление между столбцами и объектом за вас.
Рассмотрим этот сложный объект User :
На некоторых экранах нам не нужно отображать всю эту информацию. Таким образом, вместо этого мы можем создать объект UserMinimal , который содержит только необходимые данные.
В классе DAO мы определяем запрос и выбираем правильные столбцы из таблицы users .
5. Контроль зависимостей между сущностями с внешними ключами
Даже несмотря на то, что Room напрямую не поддерживает связи между сущностями, он позволяет вам определять зависимости между объектами с помощью внешних ключей.
В Room есть аннотация @ForeignKey, которая является частью аннотации @Entity. По функциональности она аналогична внешним ключам в SQLite. Она гарантирует сохранение связей между сущностями при изменениях в базе данных. Чтобы добавить её, определите объект, на который необходимо ссылаться, а также столбцы в текущем объекте и том, на который ссылаетесь.
Рассмотрим класс User и Pet . У Pet есть владелец — идентификатор пользователя, на который ссылается внешний ключ.
При желании вы можете определить, какое действие необходимо предпринять, когда родительский объект удаляется или обновляется в базе данных. Вы можете выбрать один из следующих вариантов: NO_ACTION , RESTRICT , SET_NULL , SET_DEFAULT или CASCADE , которые ведут себя так же, как в SQLite.
Примечание: в Room SET_DEFAULT работает как SET_NULL , т.к. Room ещё не позволяет устанавливать значения по умолчанию для столбцов.
6. Упрощение запросов один-ко-многим с помощью @Relation
В предыдущем примере User — Pet можно сказать, что есть отношение один-ко-многим: у пользователя может быть несколько питомцев. Допустим, мы хотим получить список пользователей со своими питомцами: List .
Чтобы сделать это вручную, нам понадобятся 2 запроса: один для получения списка всех пользователей и другой для получения списка домашних животных на основе идентификатора пользователя.
Затем мы будем перебирать список пользователей и каждый раз обращаться к таблице Pets .
Аннотация @Relation упростит нам жизнь: она автоматически запросит связанные объекты. @Relation можно применять только к List или Set . Обновим класс UserAndAllPets :
В DAO мы определяем один запрос, а Room будет запрашивать таблицы Users и Pets и самостоятельно сопоставлять объекты.
7. Избежание ложных уведомлений observable-запросов
Допустим, вы хотите получить пользователя по его идентификатору с помощью observable-запроса:
Вы будете получать новый объект User каждый раз, когда он будет обновляться. Но вы также получите этот объект, когда в таблице Users произойдут другие изменения (удаления, обновления или вставки), которые не имеют никакого отношения к интересующему вас пользователю, что приведёт к ложным уведомлениям. Более того, если ваш запрос включает в себя несколько таблиц, вы будете получать новые сообщения всякий раз, когда что-то поменяется в любой из них.
Вот что происходит за кулисами:
- В SQLite есть триггеры, которые срабатывают всякий раз, когда в таблице происходит DELETE , UPDATE или INSERT .
- Room создаёт InvalidationTracker, который использует Observers , которые отслеживают все изменения в наблюдаемых таблицах.
- И LiveData -, и Flowable -запросы полагаются на уведомление InvalidationTracker.Observer#onInvalidated. Когда оно получено, происходит повторный запрос.
Room знает только то, что таблица была изменена, но не знает, почему и что изменилось. Следовательно, после повторного запроса результат запроса передаётся с помощью LiveData или Flowable . Т.к. Room не хранит никаких данных в памяти, он не может определить, те же самые это данные или нет.
Вы должны убедиться, что ваш DAO фильтрует запросы и реагирует только на необходимые объекты.
Если observable-запрос реализован с использованием Flowables , используйте Flowable#diverUntilChanged.
Если ваш запрос возвращает LiveData , вы можете использовать MediatorLiveData , которая будет получать только нужные объекты из источника.
В ваших DAO метод, который возвращает LiveData , сделайте public , а метод, который запрашивает базу данных, protected .
Полный пример кода смотрите здесь.
Примечание: если вы запрашиваете список для отображения, обратите внимание на библиотеку Paging Library, которая будет возвращать LivePagedListBuilder. Библиотека поможет автоматически вычислить разницу между элементами списка и обновить ваш пользовательский интерфейс.
Источник
Room: Хранение данных на Android для всех и каждого
Room — это новый способ сохранить данные приложений в Android-приложении, представленный в этом году на Google I/O. Это часть новойAndroid Architecture, группа библиотек от Google, которые поддерживают уместную архитектуру приложений. Room предлагается в качестве альтернативы Realm, ORMLite, GreenDao и многим другим.
Room — это высокоуровневый интерфейс для низкоуровневых привязок SQLite, встроенных в Android, о которых вы можете узнать больше в документации. Он выполняет большую часть своей работы во время компиляции, создавая API-интерфейс поверх встроенного SQLite API, поэтому вам не нужно работать с Cursor или ContentResolver.
Использование Room
Во-первых, добавьте Room в свой проект. После этого вам нужно будет передать в Room, как выглядят ваши данные. Предположим, имеется простой класс модели, который выглядит следующим образом:
Чтобы рассказать Room о классе Person, добавляем аннотицию Entity к классу и @PrimaryKey к ключу:
Благодаря этим двум аннотациям Room теперь знает, как создать таблицу для хранения экземпляров Person.
Важная вещь, которую следует учитывать при настройке ваших моделей: каждое поле, которое хранится в базе данных, должно быть общедоступным или иметь геттер и сеттер в стандартном стиле Java Beans (например, getName () и setName (имя строки)).
В классе Person теперь есть вся информация, которая требуется Room для создания таблиц, но у вас нет способа фактически добавлять, запрашивать или удалять данные из базы данных. Вот почему вам нужно будет сделать объект доступа к данным (DAO). DAO предоставляет интерфейс в самой базе данных и занимается манипулированием хранимыми данными Person.
Вот простой интерфейс DAO для класса Person:
Первое, что нужно заметить, это то, что PersonDao — это интерфейс, а не класс. Другая интересная деталь — это инструкции SQL в аннотациях Query (). Операторы SQL говорят Room, какую информацию вы хотите получить из базы данных. Они также проверяются во время компиляции. Поэтому, если вы измените подпись метода List getAllPeopleWithFavoriteColor ( название цвета ) на List getAllPeopleWithFavoriteColor ( int color ), Room выдаст ошибку во время компиляции:
И если вы сделаете опечатку в выражении SQL, например, напишите favoriteColors ( множественное число ) вместо favoriteColor ( единственное число ), Room также выдаст ошибку компиляции:
Вы не можете получить экземпляр PersonDao, потому что это интерфейс. Чтобы иметь возможность использовать классы DAO, вам необходимо создать класс базы данных. За кулисами этот класс будет отвечать за ведение самой базы данных и предоставление экземпляров DAO.
Вы можете создать свой класс базы данных всего за пару строк:
Это лишь описание структуры базы данных, но сама база данных будет жить в одном файле. Чтобы получить экземпляр AppDatabase, сохраненный в файле с именем populus-database, вы должны написать:
Если вы хотите получить все данные обо всех Person, которые находятся в базе данных, вы могли бы написать:
Преимущества использования Room
В отличие от большинства ORM, Room использует обработчик аннотации для выполнения всей своей манеры сохранения данных. Это означает, что ни ваши классы приложений, ни классы моделей не должны ничего расширять в Room, в отличие от многих других ORM, включая Realm и SugarORM. Как вы видели при ошибках с аннотациями Query () выше, вы также получаете возможность проверки корректности SQL-запросов во время компиляции, что может сэкономить вам много хлопот.
Room также позволяет вам наблюдать за изменениями данных, интегрируя их как с API LiveData Архитектурных Компонентов, так и с RxJava 2. Это означает, что если у вас сложная схема, где изменения в базе данных должны появляться в нескольких местах вашего приложения, Room делает уведомления об изменениях. Это мощное дополнение может быть включено одной строкой. Все, что вам нужно сделать, это изменить тип возвращаемых значений.
Например, этот метод:
Самое большое ограничение в Room: взаимосвязи
Самым большим ограничением в Room является то, что он не будет обрабатывать отношения с другими типами сущностей для вас автоматически, как и другие ORM. Это означает, что если вы хотите отслеживать домашних животных:
То Room выдаст ошибку компиляци, так как не знает, как сохранить отношения между Person и Pet:
Ошибка при компиляции предлагает конвертер типов, который преобразует объекты в примитивы, которые могут быть непосредственно сохранены в SQL. Поскольку List нельзя свести к примитиву, вам нужно сделать что-то другое. Это отношения «один ко многим», где у одного Person может быть много Pet. Room не может моделировать такие отношения, но она может справиться с обратными отношениями — у каждого Pet есть один Person. Чтобы смоделировать это, удалите поле для Pet в Person и добавьте поле ownerId в класс Pet:
Это приведет к тому, что Room обеспечит ограничение внешнего ключа между объектами. Room не будет вызывать отношения «один-ко-многим» и «много-к-одному», но она дает вам инструменты для выражения этих отношений.
Чтобы получить всех домашних животных, принадлежащих конкретному человеку, вы можете использовать запрос, который находит всех домашних животных с данным идентификатором владельца. Например, вы можете добавить в свой DAO следующий метод:
Стоит ли использовать Room?
Если вы уже настроили сохранение данных в своем приложении и довольны им, то ничего не изменяйте. Каждая ORM и встроенная реализация SQLite будут продолжать работать так же, как и раньше. Room — это всего лишь еще один вариант сохранения данных.
Если вы используете SQLite или собираетесь использовать его, вы должны попробовать Room. Он обладает всеми возможностями, необходимыми для выполнения расширенных запросов, одновременно устраняя необходимость писать SQL-запросы для поддержки базы данных самостоятельно.
Источник