BMI Calculator – Room

In this chapter of the BMI Calculator application we are going to integrate Room, what is a persistent library. Using Room we can store the saved BMIs in SQL database and when we open the app, then they gonna be listed in the BmisFragment.

So, what we are going to do in this chapter is first to annotate the BMI data class, then we gonna create the DAO and the database. Thenafter we will start inserting the BMIs into the database, and finally get them back at startup of the app.

So, let’s start coding. 😎

GitHub

The starter project for this lecture is available on GitHub. Just download it using the below link.

GitHub – branch data_binding_adapter

After the download, extract the app from the .ZIP file and import it in Android Studio (File -> New -> Import Project…)

Room

First of all, we have talk a bit about Room persistent library.

Room Architecture - Android development in Kotlin

Before Room we had to use database helpers and SQLite queries to insert, delete, modify etc the data, which are stored locally on the device. It wasn’t easy to handle them manually. Then Room comes to rescue us. It was released in the Google I/O 2016. Room is one of Google’s architecture component library for working with SQLite on Android.

Room has 3 important parts.

      • Entity: It represents a table in the Room database, which should be annotated with the @Entity keyword.
      • DAO: It stands for Data Access Object, which is an interface, that contains the queries to access the database. It is annotated with @DAO
      • Database: It represents the database. Because it holds a connection to the SQLite database, all operations are executed through it. It is annotated with @Database.

If you would like to know more about the Room persistent library, then check out our tutorial.
Room basics

Step 1 - Create new package

Our first task in this chapter is to create a new package, where we will have all of the files for Room.

So, click with the right mouse button on the main source set, select the “New”, then the “Package” option. In the popup window name it as “data”.

Step 2 - Create DAO

After the creation of the data package, we are going to create inside of it a new file, called “BmiDao”.

So, click with the right mouse button on the data package, and create there a New Kotlin interface with the name of “BmiDao”.

Then, annotate it with @Dao. Using it, we will tell Room that this interface is a Dao (Data Access Object) interface.

Next is to define the functions. Basically we will have 3 functions.

      • Insert: To save the BMIs in the database
      • Delete: In case we can delete the BMIs.
      • Get all BMI: At the start of the app we are going to have a list about the saved BMIs.

These functions should be also annotated by Room. For the insert function we will use the @Insert annotation, which look like below. So, paste it into the BmiDao::interface.


Insert BMI

Note the suspend modifier.  This means, thet this function is a coroutine function, so it will run in a background thread.

Next is the delete function, which is very similar to insert. So, this should be after the insert method.


Delete BMI

Finally the last method, which will get back all the saved BMIs. For this we gonna use an SQL query, which tells Room, thet we would like to fetch all entries from the BMI table.


Get all BMI

Room is fully operative with LiveDatas. When something changes in this table, then the LiveData will notify its oberservers about the changes.

Step 3 - The Entity

In the next step we are going to create the Entity for Room. It means, we gonna annotate the previously created BMI data class.

So, open it from the model package.

First, we gonna tell Room, thet this is an Entity. It will be in our database the BMI table. Paste the below line before the class.

@Entity(tableName = “BMI”)

Next, we gonna annotate the properties as well. The bmiId property will be the autogenerated primarykey of the table.

After the annotations the BMI data class should look as below.


BMI data class

Step 4 - The Room Database

Next, we are going to define the Room database, which handels the table, creates the database, follows the versions, changes, and so on. 😊

So, go back to the data package, and create there a new class and name it as “BmiDatabase”. Then, inherit the database from the RoomDatabase::class.

Next, we will annotate this class as well, which is @Database from the Room library. After the annotation, in the parentheses, we gonna list the entities of the app, which is in our case the BMI::class, then comes the version and finally we gonna tell Room, thet we won’t export the schema.

Before we will explaine the body of the class, copy and paste into it the below code.


The database

First, be sure thet your class is also an abstract class.

Thenafter we have also an abstract function, which gives back the BmiDao::class.

Next, in the companion object we will get an instance about the database.

That’s it, now you can close this class.

Step 5 - The repository

In the fifth step we gonna create the repository, where we will define functions of the database requests.

So, create again a new file in the data package, and name it as “BmiRepository”.

We won’t annotate this class, but as a parameter we will request a bmiDao instance, what we can use in the functions.

The repository looks like below.


BmiRepository

Step 6 - Use Room in the ViewModel

So, here we are, we can start using the above created Room classes to save our BMIs.

We gonna do that in the ResultViewModel::class, so open it from the result package.

Init the repository

Next, we gonna create a variable for the repository at the beginning of the ViewModel.

private val bmiRepository: BmiRepository

Then, we gonna initialize it inside of the init block. To do thet we need first the BmiDao, what we can get from the BmiDatabase.

So, finally the init block looks like below.


Init the DB

Now, you should have an error, because of the unresolved reference of the application variable. To solve this issue, we gonna change the inheritance of the ResultViewModel::class.

Currently we are extending our ViewModel by the ViewModel::class. Change it to extend the AndroidViewModel::class and request the application as the parameter. Finally, it should look like this:

class ResultViewModel(application: Application) : AndroidViewModel(application)

The LiveData of the save event

Do you remeber the Event class, what we have  implemented to handle the calculate event in the AddNewBmiFragment?

Here, when we tap on the “Save Bmi” button, then we gonna navigate to the BmisFragment.

So, at the beginning we will define 2 more LiveData variables, which will handle this event.


The save LivDatas

Save BMI

Next, we gonna create a function, what we will use a bit later inside of the result_fragment.xml layout file with Data Binding when we tap on the “Save Bmi” button.


save BMI

Note that first we gonna make a null safe call using .let on the value of the resultBmi LiveData.

Then we gonna use the viewModelScope, which is the CoroutineScope of the ViewModel. It allows us to call the suspend functions of the repository.

Dispatchers.IO means, that this scope gonna run in a background thread.

Handle click event

We almost have everything to save the BMI and navigate to the BmisFragment. For this we need the result_fragment.xml layout file, what you can find in the res->layout folders.

Add the below to the btn_saveBMI button.

android:onClick=“@{() -> viewmodel.saveBmi()}”

This line means, thet when we click on the save button, then this attribute will fire the saveBmi() function inside of the ResultViewModel.

Observe the save event

Next we gonna modify a bit the navigation function in the ResultFragment::class to observe the save LiveData insteed of handling the click event on the save button. So, open it from the result package and navigate to the setNavigateToBmisFragment() method.

There, replace the click listener with the observation of the save LiveData with the EventObserver.

Now the method should look like below.


Observe the LiveData

Step 7 - Get all BMIs from Room

In the last step we gonna get back the saved BMIs from the Room database to be sure that the save was correct.

Extend the BmisViewModel

For this open up the BmisViewModel::class from the bmis package and paste there the below lines to initalize there the repository also.


Init the repo

Then change the header of this calls to extend the  AndroidViewModel::class.

Thenafter we can get back the BMIs using the allBmi method from the repository and we can store the list in a LiveData.

Finally the BmisViewModel look like below.


BmisViewModel

Setup an Observer

In this chapter we won’t implement the RecyclerView to have the list on the screen. Insteed we just create a log message about the list of the stored BMIs.

For this, open the BmisFragment from the bmis package and paste the below observer into the onActivityCreated() method.


Observer of the BMIs' list

Run the app

Finally, run the app. First save a BMI then check out the Logcat in Android Studio. If you search for “list of BMIs” then you can filter the log messages.

GitHub

The source code is available on GitHub under the branch room, check out using the below link.

GitHub – branch room

Questions

I hope the description was understandable and clear. But, if you have still questions, then leave me comments below! 😉

Have a nice a day! 🙂

Follow and like us:

Click to rate this post!

[Total: 0 Average: 0]

Leave a Reply

Your email address will not be published. Required fields are marked *