Why use Dependency Injection in our project?
Dependency Injection is a common technique used across the programming world to provide classes instead of writing or creating them by ourselves. This also prevents having boilerplate code and trying to instantiate or maintain instances of classes by ourselves. It encourages code reusability and maintains our code architecture well.
Hilt Introduction —
The Hilt is a dependency injection library provided by Google (Jetpack Libraries) which helps reduce the boilerplate code for manual dependency injection in our project. It is built on top of Dagger (another Google library) to simplify and ease the code with pre-defined bindings, qualifiers, and scope annotations.
Implementation —
In this article, I will use Hilt to inject Network (Retrofit here) instance and Room Instance to access the local database easily in our MVVM Architecture codebase.
First Step —
The First Step in the process would be to add the necessary Hilt related dependencies —
Second Step —
Now we will define an Application class in our project. Create a new class and extend it with ‘Application’. Now in the AndroidManifest.xml, add an entry for the name in the <application> tag and specify the application file as its value.
We will now annotate the class with ‘@HiltAndroidApp’ annotation. This is done to trigger Hilt’s code generation and also maintains a base class for application-level dependency injections. This will also attach itself to the Application lifecycle, creating it on — onCreate and destroying it on — onDestroy of the Application.
Third Step —
Now we will add annotations to our Activity as well as Fragments.
We will annotate our Activities and Fragments with — ‘@AndroidEntryPoint’ annotation. This will provide dependencies to other classes in our project.
Other types of annotations are captured here.
Note — If a fragment annotated with ‘@AndroidEntryPoint’, the annotation is to be added in all the activities where the fragment is used.
Fourth Step —
Now we will create our module and use it to inject the instance directly in our Repository class (In MVVM — Data Access is handled in Repository class). To do so, we will use few other annotations — ‘@Module’, ‘@InstallIn’, ‘@Provides’, and ‘@Singleton’.
‘@Module’ annotation is used for injecting modules that cannot be constructor-injected. To simply this, we can constructor inject something we own but in our case, Retrofit is an external library that we do not own. Thus we will provide an instance of it and use ‘@Module’ to provide it to our Android classes.
‘@InstallIn’ annotation is used to define which level should it be injected. Ex — Application level, Activity level, ViewModel level. It will obey the lifecycle of the specified level. We have used SingletonComponent. For other types, please refer here.
‘@Provides’ annotation is used where we cannot constructor-inject a type and ‘@Singleton’ is used to define that only one instance should exist.
Similarly, for Room, we can create another module like —
Fifth Step —
The final step now is to use the instances we have provided. To do so, we will now move to our Repository class and straightaway inject the instance in the constructor of the Repository class using ‘@Inject’ annotation.
And that’s it! No more instantiating Retrofit and Room DB every time or maintaining it by yourself. It is now going to be magically (not so magical as it felt in the beginning) provided to you by Hilt.
Hilt can also be used to inject different types of Interceptors for specific requests. To read more, please visit the official docs on Hilt by Google.
The Hilt is still in beta so please use it with caution as there can be bugs that could disrupt our application. On a personal note, I’ve used it in a production project and it works quite well.
MVVM Series –
- Using Pagination Library For Android Recycler View In MVVM Architecture.
- Using Hilt To Provide Network & Room Instance in MVVM Architecture.
- Guide to using Retrofit in MVVM Architecture with Hilt & RxJava — Kotlin.