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.

5 (5) · 1 Review

Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

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:

  1. Get an instance of Realm, using RealmConfiguration.
  2. Use executeTransactionAwait() with Dispatchers.IO to execute a transaction in a background thread and wait until it finishes.
  3. Create a new PetRealm object.
  4. 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:

Adding a new pet

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:

  1. Get an instance of Realm.
  2. Use executeTransactionAwait().
  3. Create the new object.
  4. 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:

Adding an owner

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:

  1. Get the Realm instance.
  2. Use executeTransactionAwait().
  3. Use where(PetRealm::class.java) to retrieve PetRealm objects.
  4. findAll() executes the query and returns every PetRealm object.
  5. Map PetRealm to Pet 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:

  1. Get the Realm instance.
  2. Use executeTransactionAwait().
  3. Use where(OwnerRealm::class.java) to retrieve OwnerRealm objects.
  4. findAll() executes the query.
  5. Map OwnerRealm to Owner 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:

Pet added

Owner added

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:

  1. Condition to filter PetRealm objects that have isAdopted as false.
  2. 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.
  3. Condition to filter PetRealm objects that have their petType 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:

Pets to adopt screen

Select a pet type from the top spinner:

Filtered pets screen

Great! You have fixed the bug and implemented the filtering functionality. Now, you can add a slight improvement to the owners list.