BMI Calculator – RecyclerView

In this chapter of the BMI Calculator application tutorial we are going to start using the RecyclerView, what we have already added to the bmis_fragment.xml file.

In this chapter first, we will create an Adapter and a ViewHolder, which won’t have a difficult layout. Thenafter we will create a Data Binding Adapter, which will send the items for the RecyclerView.

GitHub

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

GitHub – branch room

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

RecyclerView

This chapter assumes, that you have worked already with RecyclerView. If you haven’t, then it is recommended to check out our basics tutorial under the link.

RecyclerView basics

Step 1 - Create the layout for the item

Our first task in this chapter is to create a new layout file for the items of the ReceyclerView.

So, go to the res->layout folder, click on it with the right mouse button, select the “New”, then the “Layout Resource File” option. In the popup window name the file as “item_bmi”.

In this layout we gonna use Data Binding also. So, move your mouse to the root view (ConstraintLayout), and press Alt+Enter on Windows or Control/Option+Enter on Mac. This will open up a quick menu, the Show Context Actions menu. There, select to first option, which is “Convert to data binding layout”. Now the layout should look like below.


layout of item using Data Binding

Variables of the layout

In the layout file we can define variables as well. In our case we gonna have 2 variables. One will hold the data of one BMI item, the second one will be the instance of the BmisViewModel::class.

The below variables go into the tags.


Variables

Be careful with the package path of the above variables, because the packages have to be raplaced with your project’s package.

The Views of the layout

Next, we gonna implement the Views of the layout, which means we gonna modify the content of the ConstraintLayout.

It is very simple, so we won’t go into the details of it. If you have questions, then leave a comment below. 😊

So, just copy and paste the below views into the ConstraintLayout.


The views of the item

Binding data

Next is to bind the data with the above created bmi variable.

So, copy and paste the below attributes to the corresponding views.

      • view_bmiState
        • app:setBmiStateColor=“@{bmi.bmi()}”
        • app:context=“@{context}”
      • tv_bmi
        • android:text=“@{@string/calculated_bmi(bmi.bmi())}”
      • tv_weight
        • android:text=“@{@string/weight_in_kg(bmi.weight)}”
      • tv_date
        • android:text=“@{bmi.date}”

These lines should be already known by you, because we have used them already in the result_fragment.xml file.

Later we will come back to handle the clicks, but for now we are done.

Step 2 - Binding Adapter for the View

In the last step we have added the setBmiStateColor to the View, but still it won’t work, because we have to define this BindingAdapter for the View . So, open up the DataBindingAdapter from the utils package and paste there the below function.


setBmiStateBolor

Step 3 - Create the adapter

Our third task in this chapter is to create the adapter for the RecyclerView. It means, we gonna create a new file, which file will contain the Adapter and the ViewHolder as well.

After them, we gonna define a DiffUtil as well, which calculates the minimum number of changes between the old and the new list that’s been passed to the ReceyclerView.

So, create a new file in the bmis package, and name it as “BmisListAdapter”.

The ViewHolder

We are going to start the implementation with the  ViewHolder. So, create a class indside of the BmisListAdapter‘s class with the name of “BmiViewHolder”.

It is going to have the ItemBmiBinding::class as a private constructor, and it has to be extended by RecyclerView.ViewHolder.


Header of the ViewHolder

Now, inside of the BmiViewHolder::class, we will bind the variables, what we have created in its layout.


Bind the variables

Next, we gonna inflate the layout inside of the companion object. It means, we can reach this method without having to instantiate the ViewHolder.


Inflate the layout

Calculating the differences

In this step we will define a callback, which will help us to compare 2 lists and it will calculate the differences between the lists, and the minimum number of changes between the old and the new list.

So, copy and paste the class into the BmisListAdapter.kt file, and be careful to do it outside of the BmisListAdapter::class.


The DiffUtil

Finishing the adapter

We are almost finished the adapter, only few things left.

The first thing is that we have to pass the BmisViewModel as constructure of the BmisListAdapter. Then we have to extend the adapter also.

Below you can see the header of the class.


The header

Now, because we have extended our adapter, we have to implement some methods.


Override methods

In the above methods we are just inflating the layout and passing the items for the ViewHolder.

That’s all, the adapter is finished. 😊

Step 4 - Bind the items

Our adapter is already finished, but still we haven’t uploaded any items to it. To solve this task, we gonna use Data Binding Adapter and we gonna create again a custom attribute for the RecyclerView.

So, open the DataBindingAdapter.kt file from the utils folder and paste the method at the end.


setItems Data Binding Adapter

Note that the name of the attribute is defined after the annotation.

Then see how we have defined the header of the function, because the first attribute has to be always the type of the view, where we can use the attribute.

Next, open the bmis_fragment.xml file from the res->layout folders and paste the below variable to the tags.


viewmodel variable

Now, we are able to pass the list of the items for the before created items attribute. The list is available in the BmisViewModel::class.

So, add the below line to the RecyclerView.

app:items=“@{viewmodel.items}”

Step 5 - Setup the ListAdapter

In this step we will setup some things in the BmisFragment::class.

The first thing is thet we have to provide the BmisViewModel for the viewmodel variable inside of the layout file. So, add the below line to the onCreateView() method, directly before its return line.

binding.viewmodel = viewModel

Then this call to the onActivityCreated() method.

setupListAdapter()

It is still red, so paste into the class its method.


setupListAdapter()

Remove the observer

Previously we have created an obersver for the items’ list. Because of the Data Binding Adapter we don’t need it anymore. So, still in the BmisFragment::class go to the onActivityCreated() method and remove the item LiveData observer (it contains a Log).

Add the lifecycleowner

To have a working LiveData observer inside of the layout file, we have to provide the lifecycleowner of the view.

So, still in the onActivityCreated() method add the below line.

binding.lifecycleOwner = viewLifecycleOwner

You have to provide for Data Binding the lifecylcerowner, otherwise it won’t observe the LiveData.

Run the app

It’s time to run the app. If you have saved any BMIs before, then you should have them in your list.

Step 6 - Delete BMI

After… hopefully … a successful run, we are going to implement the delete feature. It means, when we press for a longer time an item inside of the RecyclerView, then a Bottom Sheet Dialog will popup where we will get a question to be sure we would like to delete the BMI and the action button for the delete.

BmisViewModel

So, open the BmisViewModel::class from the bmis package and add to it the below LiveData and 2 functions.


Delete BMI

The deleteBmiDialog LiveData will notify the BmisFragment that we have longpressed the item and it will open the Bottom Sheet Dialog.

item_bmi.xml

The 2 functions will be called from the layout of the item. So, open the item_bmi.xml file from the res->layout folder and add the below attribute to the ConstraintLayout.


Longpress

Now you should have an error, because we haven’t defined the bmi variable inside of the layout file yet.

So, copy and paste the below bmi variable into the <data>/<data> tags, where you have already the viewmodel variable.


bmi variable

BmisListAdapter

Next we have to add this bmi variable to the BmiViewHolder also. So open the BmisListAdapter::class and add the below line to the bind() method, what you can find in the BmiViewHolder.

binding.bmi = bmi

BmisListAdapter

For the Bottom Sheet Dialog we need a layout also, which will be very simple, because it will contain only a TextView and 2 Buttons.

So, click with the right mouse button on the res->layout folder, select “New”, then the “Layout Resource file” option. In the popup window name it as “dialog_bottomsheet_deleteitem”.

Thenafter comes the xml code for the layout, what you can find below.


Layout of the bottom sheet

BmisFragment

The next step is to setup the Bottom Sheet Dialog inside of the BmisFragment::class, so open it from the bmis package.

Then, add the below method call to the onActivityCreated() function.

setupDeleteBmiDialog()

Still this line will be in red, so paste after the onActivityCreated() function the below method.


setupDeleteBmiDialog()

Run the app

Run again the app and try out the delete feature. Longpress on an item of the RecyclerView. Then the delete Bottom Sheet Dialog should be opened at the bottom of the screen. Finally press the Delete button.

GitHub

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

GitHub – recyclerView

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]

2 thoughts on “BMI Calculator – RecyclerView”

  1. import com.example.bmicalculator2.databinding.BmiItemBindingImpl;
    ^
    symbol: class BmiItemBindingImpl

    cannot find symbol

    I think this BmiItemBindingImpl class is not getting generated.
    Not sure how to resolve this error.
    Please help!!

Leave a Reply

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