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
Inserting Objects to the Realm
Inserting objects to the database is part of Realm’s write transactions. All operations should happen in a transaction. A transaction is a group of read and write operations Realm executes as a single operation. Every operation in the transaction should succeed for the transaction to complete successfully. If any operation fails, then the entire transaction fails.
Open PetDatabaseOperations.kt file in the realm package. Add the following parameter to the class constructor:
private val config: RealmConfiguration
With this line, you provide RealConfiguration
to this class.
Modify insertPet()
as follows:
suspend fun insertPet(name: String, age: Int, type: String, image: Int?) {
// 1.
val realm = Realm.getInstance(config)
// 2.
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
// 3.
val pet = PetRealm(name = name, age = age, petType = type, image = image)
// 4.
realmTransaction.insert(pet)
}
}
Import io.realm.Realm
, io.realm.kotlin.executeTransactionAwait
and kotlinx.coroutines.Dispatchers
.
In this code, you:
- Get an instance of Realm, using
RealmConfiguration
. - Use
executeTransactionAwait()
withDispatchers.IO
to execute a transaction in a background thread and wait until it finishes. - Create a new
PetRealm
object. - Insert the new
PetRealm
object.
It’s crucial that you use the Realm instance, called realmTransaction
in the code above, provided in the lambda function to insert the newly created object.
Build and run the app. Press the add button and add a new pet as follows:
Press Add Pet and you’ll insert the new pet to the database. You’ll have to trust me on this, because the app doesn’t display anything yet.
Add the code to insert an owner. Open OwnerDatabaseOperations.kt and add the following parameter to its constructor:
private val config: RealmConfiguration
This line provides RealmConfiguration
to this class.
Modify insertOwner()
as follows:
suspend fun insertOwner(name: String, image: Int?) {
// 1.
val realm = Realm.getInstance(config)
// 2.
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
// 3.
val owner = OwnerRealm(name = name, image = image)
// 4.
realmTransaction.insert(owner)
}
}
This code follows the same steps as adding a pet:
- Get an instance of Realm.
- Use
executeTransactionAwait()
. - Create the new object.
- Insert it in the database.
Build and run the app. Press the Owners button. Add a name and long-press an image to select it, as follows:
Press Add Owner and you’ll have to trust me again that you added the new owner to the database.
Don’t worry. The next step is to learn how to query the database and display the information.
Querying the Realm
Realm provides a query engine that allows you to find, filter and sort objects. Each query result is a live object. This means it contains the latest data and, if you decide to modify the result, it will modify the stored object.
Open PetDatabaseOperations.kt. Add the following code at the end of the class:
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
)
}
mapPet()
maps the PetRealm
object to the Pet
UI object.
Modify retrievePetsToAdopt()
the following way:
suspend fun retrievePetsToAdopt(): List<Pet> {
// 1.
val realm = Realm.getInstance(config)
val petsToAdopt = mutableListOf<Pet>()
// 2.
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
petsToAdopt.addAll(realmTransaction
// 3.
.where(PetRealm::class.java)
// 4.
.findAll()
// 5.
.map {
mapPet(it)
}
)
}
return petsToAdopt
}
To retrieve pets up for adoption, you:
- Get the Realm instance.
- Use
executeTransactionAwait()
. - Use
where(PetRealm::class.java)
to retrievePetRealm
objects. -
findAll()
executes the query and returns everyPetRealm
object. - Map
PetRealm
toPet
objects.
Now that you’re on a roll, open OwnerDatabaseOperations.kt and modify retrieveOwners()
as follows:
suspend fun retrieveOwners(): List<Owner> {
// 1.
val realm = Realm.getInstance(config)
val owners = mutableListOf<Owner>()
// 2.
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
owners.addAll(realmTransaction
// 3.
.where(OwnerRealm::class.java)
// 4.
.findAll()
// 5.
.map { owner ->
Owner(
name = owner.name,
image = owner.image,
id = owner.id
)
}
)
}
return owners
}
To retrieve the owners, you:
- Get the Realm instance.
- Use
executeTransactionAwait()
. - Use
where(OwnerRealm::class.java)
to retrieveOwnerRealm
objects. -
findAll()
executes the query. - Map
OwnerRealm
toOwner
objects.
Now, build and run the app. You’ll see the pets you added previously. If you navigate to the Owners screen, you see the owner you added too:
Well done! Now you can see data from the database. However, there’s a bug, and you can make a couple improvements.
Filtering Results
The bug with retrieving pets is that the query will return every pet, both adopted and in adoption. But Realm provides filtering operators that help filter the results based on certain values.
In PetDatabaseOperations.kt, modify retrievePetsToAdopt()
by adding the following line after .where()
:
.equalTo("isAdopted", false)
This operation will return only the instances of PetRealm
that have isAdopted
as false
.
Now, modify retrieveAdoptedPets()
, like this:
suspend fun retrieveAdoptedPets(): List<Pet> {
val realm = Realm.getInstance(config)
val adoptedPets = mutableListOf<Pet>()
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
adoptedPets.addAll(realmTransaction
.where(PetRealm::class.java)
.equalTo("isAdopted", true)
.findAll()
.map {
mapPet(it)
}
)
}
return adoptedPets
}
To retrieve the adopted pets, isAdopted
should be true
.
You can now implement the filter by pet type in the “Pets to adopt” list. Modify retrieveFilteredPets()
as follows:
suspend fun retrieveFilteredPets(petType: String): List<Pet> {
val realm = Realm.getInstance(config)
val filteredPets = mutableListOf<Pet>()
realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->
filteredPets.addAll(realmTransaction
.where(PetRealm::class.java)
// 1.
.equalTo("isAdopted", false)
// 2.
.and()
// 3.
.beginsWith("petType", petType)
.findAll()
.map {
mapPet(it)
}
)
}
return filteredPets
}
This code executes a transaction to retrieve PetRealm
objects. The filtering works the following way:
- Condition to filter
PetRealm
objects that haveisAdopted
asfalse
. -
and()
is a logical operator that indicates the result should meet both conditions. Here you can find a list of all the logical operators Realm supports. - Condition to filter
PetRealm
objects that have theirpetType
field with the provided value.
After executing the query and mapping the results to Pet
objects, the method returns the list with pets of the selected petType.
Build and run the app. Add different kinds of pets to the list as shown in the next image:
Select a pet type from the top spinner:
Great! You have fixed the bug and implemented the filtering functionality. Now, you can add a slight improvement to the owners list.