Dependency injection (DI) is a technique widely used in programming and well suited to Android development, where dependencies are provided to a class instead of creating them itself.
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.
As HILT is built on top of Dagger dependency injection library. Compare to Dagger the goals of HILT are as follows:
To simplify Dagger-related infrastructure for Android apps.
To create a standard set of components and scopes to ease setup, readability, and code sharing between apps.
To provide an easy way to provision different bindings to various build types, such as testing, debug, or release.
HILT is integrated with Jetpack libraries and Android framework classes and removes most of the boilerplate to let you just focus on important parts.HILT automatically generates and provides:
Components for integrating Android framework classes with Dagger that you would otherwise need to create by hand.
Scope annotations for the components that HILT generates automatically.
Predefined bindings and qualifiers.
We are what we repeatedly do. Excellence, then, is not an act, but a habit. Try out Justly and start building your habits today!
To setup HILT in the project, we need to add the following dependencies in app level build.gradle file,
// Dagger - Hilt
implementation "com.google.dagger:hilt-android:{latest-version}"
kapt "com.google.dagger:hilt-android-compiler:{latest-version}"
//hiltViewModel
implementation 'androidx.hilt:hilt-navigation-compose:{latest-version}'
Then as a next step, we need to apply the Dagger/HILT plugin at the top of the app level build.gradle file like this:
plugins {
...
id 'dagger.hilt.android.plugin'
}
and finally, we need to add the following classpath at project level build , gradle like this:
dependencies {
...
classpath "com.google.dagger:hilt-android-gradle-plugin:{latest-version}"
}
This is the required setup to get started with Dagger/HILT.
Step 1:
We will fist add Application class AppClass like this:
class AppClass: Application()
and we will update the Manifest file like this:
android:name=".AppClass"
now, enable HILT in our app by annotating our application class with @HiltAndroidApp to trigger HILT’s code generation:
@HiltAndroidApp
class AppClass: Application()
The above step is a mandatory one, it generates all the component classes which we have to do manually while using Dagger.
Step 2:
Now, we will add the dependency for retrofit as we want to fetch data from API. Coil is used as a Image Loading library
we are going to use this API , to fetch movie data.
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.2"
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
//coil
implementation "io.coil-kt:coil-compose:1.3.2"
Our data class for Movie will look like this:
data class Movie(val name: String, val imageUrl: String,
val desc: String, val category: String)
Our ApiService will look like this:
interface ApiService {
@GET("movielist.json")
suspend fun getMovies(): List<Movie>
}
Step 3:
Now, we will create Networkmodule object , here we need not to create ApplicationComponent as we are going to use the one provided by Dagger/HILT.
@Module
object NetworkModule {}
Here @Module annotation will help HILT to understand that this class is a module.
Now, we need to plug this module class in the specific component. In our case we need to add this at application level so we will install it in SingleComponent like this:
@InstallIn(SingletonComponent::class)
@Module
object NetworkModule {}
Here, we have used @InstallIn annotation to install it in SingletonComponent which is provided by Dagger/HILT.
@InstallIn(SingletonComponent::class)
To know more about HILT components and how they are used click here.
Step 4:
Now, inside out NetworkModule, we will provide all the dependencies one by one, our Network module will look like this:
@InstallIn(SingletonComponent::class)
@Module
object NetworkModule {
@Singleton
@Provides
fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl("https://howtodoandroid.com/apis/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
}
@Singleton
@Provides
fun provideApiService(retrofit: Retrofit): ApiService {
return retrofit.create(ApiService::class.java)
}
}
Here, we have provided two dependencies, Retrofit (which will be used by provideApiService) and provideApiService.
Dependencies are provided using @Provides annotation. @Singleton annotation helps the instance to be created and used once across the whole app.
Step 5:
Now , as everything is setup we can inject the dependencies into the classes.
To make an Android class supported by Dagger-HILT we use,
@AndroidEntryPoint
class MainActivity : ComponentActivity() {}
Here, @AndroidEntryPoint means Dagger/HILT can now inject dependecies in this class.
@AndroidEntryPoint annotation can be used in Activity
Inside our MainActivity we have used hiltViewModel, and instance of our viewModel can be created with the help of @AndroidEntryPoint
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
JetpackTheme {
val mainViewModel = hiltViewModel<MainViewModel>()
// A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) {
MovieList(movieList = mainViewModel.movieListResponse)
mainViewModel.getMovieList()
}
}
}
}
}
And Finally our mainViewModel will look like this:
@HiltViewModel
class MainViewModel @Inject constructor(private val apiService: ApiService) : ViewModel() {
var movieListResponse: List<Movie> by mutableStateOf(listOf())
var errorMessage: String by mutableStateOf("")
fun getMovieList() {
viewModelScope.launch {
try {
val movieList = apiService.getMovies()
movieListResponse = movieList
} catch (e: Exception) {
errorMessage = e.message.toString()
}
}
}
}
Here, we can see we have used @Inject annotation in the ViewModel object’s constructor to provide ApiService Dependency. Here, HiltViewModel will be used to generate instance of viewModel.
This way we can Inject dependency using Dagger/HILT inside our app.
You can find complete Jetpack compose with Dagger/HILT project here.
Hope this will help you start with Dagger/HILT.
Thanks for your support!