BMI Calculator – Hilt

BMI Calculator – Hilt

In this lecture of the BMI Calculator sample application we are going to refactor our app and we are going to start using Hilt, which is a new dependency injection framework for Android.

GitHub

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

GitHub – branch recyclerView

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

Dependency Injection

First of all, we have to talk about what does Dependency Injection mean. In software engineering, dependency injection is a technique, a design pattern whereby one object supplies the dependencies of another object.

We can create the dependent object outside of the class and provide those object to class from different ways. DI can help with, moving the creation and binding of the dependent objects outside of the class that depends on them.

In this chapter we are going to refactor the code to use Hilt, which is a new dependency injection framework for Android development.

Hilt

To summarize in a few words what is Hilt, I gonna show you the official description from the Android developer site.

Hilt is a dependency injection library for Android that reduces the boilerplate of doing manual dependency injection in your project.

Hilt provides a standard way to use DI in your application by providing containers for every Android class in your project and managing their lifecycles automatically. Hilt is built on top of the popular DI library Dagger to benefit from the compile-time correctness, runtime performance, scalability, and Android Studio support that Dagger provides.

Source: developer.android.com

Dagger 2 is a very popular dependency injection framework on Android. It works with annotation processors which generates readable code for the developer as well.

Most used annotations in Hilt:

      • @HiltAndroidApp: The apps, which using Hilt, have to have an Application::class, which is annotated with @HiltAndroidApp. This triggers Hilt to genereate its code.
      • @AndroidEntryPoint: Hilt provides dependencies for Android classes (Activity, Fragment, Service…) which are annotated with this annotation.
      • @Inject: It requests dependencies and can be used on a constructor, a field, or on a method.
      • @Module: It defines classes and methods which provide dependencies.
      • @InstallIn: In Hilt modules has to be annotated with @InstallIn. It tells Hilt in which Android class we want to use the module.
      • @Binds: We can use this annotation to tell Hilt which implementation we want to use as an instance of an interface.
      • @Provides: Contstructor injection is not possible if you don’t own the class, like Retrofit or Room. In this case you can provide instances with @Provides.

Step 1 - Add the dependency

We are going to start this chapter by adding the dependencies of Hilt to the app. Frist, open the Module build.gradle file from the left Project pane.

Then, at the top of the file add the below line.

apply plugin: ‘dagger.hilt.android.plugin’

Thenafter, add the below lines to the dependencies{} section of the file.


Dependencies of Hilt

The third step is to add one more line to Gradle, but in this case to the Module build.gradle file. You can find this file also in the Gradle Scripts.

Then, also in the dependencies{} section add the below line.


Dependency of Hilt

Next sync the project by clicking on the Sync now button at the top right corner of Android Studio.

Step 2 - Add Hilt to apps lifecycle

To start using Hilt in our app, we have to add it to the lifecycle of the app. We can do it by creating a class, which extends the Application::class.

So, create a new class, called “MyApp” in the main source set.

Thenafter annotate it with @HiltAndroidApp and extend it with the Application::class. The file now should look like below.


Start using Hilt in our app

@HiltAndroidApp triggers Hilt’s code generation, including a base class for your application that serves as the application-level dependency container.

Source: developer.android.com

One more thing what we should do in this step is to add this MyApp to the AndroidManifest.xml file, what you can find in the manifest folder.

Add the below attribute into the tag <application>, but before the first <activity> tag.

android:name=“.MyApp”

Step 3 - The Hilt module

The next step is to create a module, which tells Hilt how to create instances about classes where we can’t use constructor or field injection. In our case, the module will help Hilt to create an instance about the BmiDatabase of Room and about the BmiDao classes. This instances are going to be available in the whole lifecycle of the app.

Frist of all, we have to create a new package in the main source set with the name “di.module”. Inside of this new package create a new Kotlin file also and name it as “BmiDatabaseModule”.

Paste into it the below lines.


BmiDatabaseModule

At the beginning of this chapter we were talking about the annotations what we are using in the module class.

      • @Module: This annotation tells Hilt how to create instances about the Database and DAO classes.
      • @InstallIn(ActivityComponent::class): This annotation means, that this module will be available in the entire app.
      • @Singleton: It means that only one instance will be created during the lifetime of our app.
      • @Provides: This annotation provides the instance of the types.

Step 4 - The Repository interface

Before we can start the refactoring of the ViewModels, we have to refactor a bit the Room repository as well. So, open it from the data package.

First, move your cursor to the name of the class, and there press Shift+F6 (Win/Mac), raname it and all the usages to BmiRepositoryImpl”.

Next, using your mouse, click with the right button on the name of the class. Then, from the popup window select Refactor, and the Extract interface option.

Thenafter select the second “Extract to separate file” option.

In the popup window name the interface as “BmiRepository” and check in all the members. The rest can stay as it is, so click on the Refactor button.

Next step of the refactoring is to extend the header of the repository’s implementation to inject into it the BmiDao::class. So add the “@Inject constructor” to its header. You can see it below.


@Inject constructor

Step 5 - Refactoring of the ViewModels

Because we gonna create the Database and the DAO instances using Hilt and it will be singleton, which means only one instance will be created in the whole lifetime of the app. So, we won’t need to do it inside of the ViewModels.

In Hilt we don’t have to create ViewModelFactory to instantiate our ViewModels. Insteed, we can just annotate the constructor with @ViewModelInject.

BmisViewModel::class

Open up the BmisViewModel::class from the bmis package.

Currently its header looks like below.


BmisViewModel::class

Change it to:


New header of the ViewModel

Note that we have changed the inheritance of the class from AndroidViewModel to ViewModel. We did it, because we don’t need anymore the context of the appliction in the ViewModel.

Thenafter you should have an error, because the variable of the repository is defined in this class also. To fix this issue, remove the variable of the repository from the body of the ViewModel. Then remove the init block also.

After the refactoring, the BmisViewModel::class should look like below.


The refactored ViewModel

AddNewBmiViewModel::class

The next step is to add the constructor injection to the AddNewBmiViewModel::class also. So, open the file from the addnewbmi package.

The task here is just to extend the header of the class with “@Inject constructor”.


Refactoring of the AddNewBmiViewModel

ResultViewModel::class

The last ViewModel is the ResultViewModel. Here our task is the same like it was in case of the BmisViewModel:

      1. Inject the repository in the constructor
      2. Remove the variable of the repository from the body of the class.
      3. Remove the init block.

Thenafter the ResultViewModel looks like below.


Refactoring of the ResultViewModel

Step 6 - @AndroidEntryPoint

Hilt can provide dependencies for Android classes using the annotation of @AndroidEntryPoint. If we annotate an Android class with @AndroidEntryPoint, then must annotate the Android classes which are depend on it.

In our case it looks like that we have to annotate with @AndroidEntryPoint the MainActivity::class and the 3 Fragments also.

Note that Hilt support Android classes which 

      • Extends ComponenetActivity, like AppComponentActivity
      • Extends androidx.Fragment.

So open up the MainActivity::class from the main source set and annotate the class with @AndroidEntryPoint.

Then do the same with our 3 fragments also.

      • BmisFragment
      • AddNewBmiFragment
      • ResultFragment

Run the app

Finally, it’s time to run the app. It should work as before. 😎

Congratulations!
You just started using Hilt, Android’s dependency injection framwork in you app. 😊

GitHub

The source code is available on GitHub under the branch hilt, check out or download it using the below link.

GitHub – hilt

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 *