Realm Database on Android: Getting Started
Learn how to use Realm database on Android for data persistence. You’ll learn how to add it to your android app and utilize its features. By Rodrigo Guerrero.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Realm Database on Android: Getting Started
30 mins
- Getting Started
- Introducing Realm
- Understanding Realm
- Initializing Realm
- Creating a Schema
- Inserting Objects to the Realm
- Querying the Realm
- Filtering Results
- Sorting Results
- Making Calculations
- Adding Relationships
- Defining One-to-One Relationships
- Defining One-to-Many Relationships
- Using Inverse Relationships
- Migrating the Database
- Updating Objects
- Deleting Objects
- Using Realm Studio
- Comparing Realm with Room
- Where to Go From Here
Sorting Results
Sometimes you have to sort results from the queries before displaying them on the screen. Go to OwnerDatabaseOperations.kt and add the following line to the query in retrieveOwners()
after .findAll()
:
.sort("name", Sort.ASCENDING)
Import io.realm.Sort
.
This operation sorts the results by the name field in ascending order.
Build and run the app. Add other owners to the list. You’ll see the owners sorted by name, as in the following image:
Each owner displays the number of pets it owns, but so far, that number is always zero. How can you get the number of pets using Realm?
Making Calculations
Another value you need to display is the number of pets each owner has. Realm has different aggregate operators. These operators traverse a list of Realm objects and calculate a value.
Open OwnerDatabaseOperations.kt and add the following code:
private fun getPetCount(realm: Realm, ownerId: String): Long {
// 1.
return realm.where(PetRealm::class.java)
// 2.
.equalTo("owner.id", ownerId)
// 3.
.count()
}
In this code, you:
- Query the realm to get
PetRealm
objects. - Use
owner.id
to filter by owner ID. - Count the number of pets the owner has using
.count()
Modify the Owner
creation in retrieveOwners()
to add numberOfPets
, as follows:
Owner(
name = owner.name,
image = owner.image,
id = owner.id,
numberOfPets = getPetCount(realmTransaction, owner.id)
)
You now have pets up for adoption and owners. It’s time to let the owners adopt some pets.
Adding Relationships
Realm provides a way to implement one-to-one, one-to-many and inverse relationships.
Defining One-to-One Relationships
A one-to-one relationship is when an object relates at most with one instance of another object. In PetRealm, this happens with a pet that can have at most one owner, as shown in the following diagram:
Open PetRealm.kt and add the following parameter to the class constructor:
var owner: OwnerRealm? = null
This line tells the PetRealm
object it can have at most one OwnerRealm
. But there’s another relationship in this database: One owner can have multiple pets.
Defining One-to-Many Relationships
A one-to-many relationship is when one object relates to multiple objects. This is the scenario when a single owner can have multiple pets, as shown in the following diagram:
Open OwnerRealm.kt and add the following parameter to the class constructor:
var pets: RealmList<PetRealm> = RealmList()
Import io.realm.RealmList
.
A RealmList
allows the OwnerRealm
to have a one-to-many relationship with PetRealm
.
Good job! You have implemented two relationships in PetRealm. However, Realm provides a third type of relationship that can make your life easier.
Using Inverse Relationships
The relationships you implemented are unidirectional. This means when you get the query results for pets, their owners won’t be available in the results. This is a bit of a problem, because you have to show the pet owner in the adopted pets list.
Realm provides inverse relationships to solve this. Go to PetRealm.kt and replace the owner
parameter in the constructor with the following lines:
@LinkingObjects("pets") // 1.
val owner: RealmResults<OwnerRealm>? = null // 2.
Import io.realm.annotations.LinkingObjects
and io.realm.RealmResults
.
To add an inverse relationship, you must:
- Add
@LinkingObjects
annotation, passing as parameter the name of the field you’re adding the relationship to. The field inOwnerRealm
you want to link ispets
. - The field should be
val
and of typeRealmResults
.
With this improvement, you now can get the OwnerRealm
information in the PetRealm
query.
It’s time to build and run the app. Oh no! The app crashes. Taking a look at Logcat, you’ll find the following error:
Process: com.raywenderlich.android.petrealm, PID: 16049
io.realm.exceptions.RealmMigrationNeededException: Migration is required due to the following errors:
- Property 'OwnerRealm.pets' has been added.
After adding new fields, you have to create a migration to tell the database what has changed.
Migrating the Database
Realm maps each state of the database schema to a specific version. If this schema changes, like it did when you added the relationships in the previous section, the version needs to increment. You also have to tell Realm how to handle the differences in the schema by creating a migration.
Create a new file in the realm package and name it Migrations.kt. Add the following code:
// 1.
val migration = RealmMigration { realm, oldVersion, newVersion ->
// 2.
if (oldVersion == 1L) {
// 3.
val ownerSchema = realm.schema.get("OwnerRealm")
val petSchema = realm.schema.get("PetRealm")
// 4.
petSchema?.let {
ownerSchema?.addRealmListField("pets", it)
}
}
}
Import io.realm.RealmMigration
.
To add a migration, you must:
- Create a
val
of typeRealmMigration
. - Define what to do for each version change.
oldVersion
will hold the value for the previous schema version. - Get each schema you need to modify.
-
ownerSchema
needs a newRealmList
field of typePetRealm
. UseaddRealmListField()
with the name of the field and the schema type the field needs.
Open PetsModule.kt in the di package. Increase the schema version like this:
private val realmVersion = 2L
Modify providesRealmConfig()
as follows:
RealmConfiguration.Builder()
.schemaVersion(realmVersion)
.migration(migration)
.build()
Use migration()
to add the migration. If you build and run the app, it runs again. Everything’s working as expected. It’s time for the most important step: adopting pets.
Updating Objects
To update Realm objects, you need to query for the object you want to update and assign the new values.
To adopt a pet, isAdopted
should change to true
and the pet gets assigned to the owner. Open OwnerDatabaseOperations.kt and modify updatePets()
like this:
suspend fun updatePets(petId: String, ownerId: String) {
val realm = Realm.getInstance(config)
// 1.
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
// 2.
val pet = realmTransaction
.where(PetRealm::class.java)
.equalTo("id", petId)
.findFirst()
// 3.
val owner = realmTransaction
.where(OwnerRealm::class.java)
.equalTo("id", ownerId)
.findFirst()
// 4.
pet?.isAdopted = true
// 5.
owner?.pets?.add(pet)
}
}
In this code, you:
- Add a transaction to run the write operation.
- Query for the lucky pet.
- Query for the owner who will adopt the pet.
- Update
isAdopted
value. - Add the pet to the owner’s pet list.
Open PetDatabaseOperations.kt and modify mapPet()
as follows:
private fun mapPet(pet: PetRealm): Pet {
return Pet(
name = pet.name,
age = pet.age,
image = pet.image,
petType = pet.petType,
isAdopted = pet.isAdopted,
id = pet.id,
ownerName = pet.owner?.firstOrNull()?.name
)
}
You can take advantage of the relationships you added previously and add the owner’s name to each adopted pet.
Build and run the app. Press Adopt Me in any pet and select an owner. Make a single owner to adopt several pets. Navigate to the Adopted Pets screen and you’ll see the lucky pets:
Open the Owners screen. You can see the number of pets each owner adopted.
Great job! You helped the pets find an owner. However, there could be times when a pet runs away or an owner is no longer interested in adopting. In this case, you need to be able to remove them from the app.