In modern Android development, maintaining a scalable codebase can be challenging, especially when it comes to dependency management. Hilt, which is built on top of Dagger, is a powerful dependency injection library that helps streamline dependency management. In this article, we'll explore how to implement Hilt in a Kotlin Android project using Jetpack Compose and the MVVM (Model-View-ViewModel) architecture.
This guide will cover all the necessary steps—setting up Hilt, integrating it into MVVM, and using it to manage dependencies seamlessly throughout your app. Let's dive in!
Step 1: Add Dependencies
First, we need to add the necessary Hilt dependencies to our project.
In your project-level build.gradle
file, include the Hilt Gradle plugin:
buildscript { dependencies { classpath 'com.google.dagger:hilt-android-gradle-plugin:2.x.x' // Replace with the latest version } }
In your app-level build.gradle
, add the following dependencies:
plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' id 'dagger.hilt.android.plugin' // Add this } android { ... } dependencies { // Hilt dependencies implementation "com.google.dagger:hilt-android:2.x.x" // Replace with the latest version kapt "com.google.dagger:hilt-android-compiler:2.x.x" // ViewModel for Jetpack Compose implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.x.x" // Latest Hilt ViewModel support kapt "androidx.hilt:hilt-compiler:1.x.x" // Other dependencies like lifecycle, Jetpack Compose, etc. implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.x.x" implementation "androidx.activity:activity-compose:1.x.x" }
Step 2: Apply the Hilt Plugin
To use Hilt in your project, you need to apply the Hilt plugin in your app-level build.gradle
file:
apply plugin: 'dagger.hilt.android.plugin'
Step 3: Initialize Hilt in the Application Class
Next, create an application class and annotate it with @HiltAndroidApp
. This annotation will allow Hilt to manage dependency injection at the application level:
@HiltAndroidApp class MyApp : Application() { // This will allow Hilt to perform dependency injection }
Be sure to declare this application class in your AndroidManifest.xml
:
<application
android:name=".MyApp"
...>
...
</application>
Step 4: Create the ViewModel and Repository
With MVVM architecture, the Repository is responsible for handling data operations, while the ViewModel serves as an intermediate layer between the UI and the repository.
Repository Example:
class MyRepository @Inject constructor( private val apiService: ApiService // Injecting the service to fetch data from API ) { fun fetchData(): Flow<Data> { // Example repository function return apiService.getData() } }
Annotate your ViewModel
with @HiltViewModel
so Hilt can manage its dependencies:
@HiltViewModel class MyViewModel @Inject constructor( private val repository: MyRepository ) : ViewModel() { private val _data = MutableStateFlow<Data?>(null) val data: StateFlow<Data?> = _data init { viewModelScope.launch { repository.fetchData().collect { _data.value = it } } } }
Step 5: Provide Dependencies Using Hilt Modules
You need to create a Hilt module to provide dependencies like Retrofit or any other services you use in your project.
@Module @InstallIn(SingletonComponent::class) object AppModule { @Provides @Singleton fun provideRetrofit(): Retrofit { return Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build() } @Provides @Singleton fun provideApiService(retrofit: Retrofit): ApiService { return retrofit.create(ApiService::class.java) } }
This module provides the necessary dependencies for Retrofit and ApiService
, allowing them to be injected into other parts of your app.
Step 6: Use ViewModel in Composables
To use your ViewModel
in a Jetpack Compose screen, you can inject the ViewModel
via Hilt using the hiltViewModel()
function:
@Composable fun MyScreen( viewModel: MyViewModel = hiltViewModel() // Injecting ViewModel ) { val data by viewModel.data.collectAsState() Column(modifier = Modifier.fillMaxSize()) { Text(text = data?.toString() ?: "Loading...") } }
Step 7: MainActivity Setup
Finally, annotate your MainActivity
with @AndroidEntryPoint
to let Hilt know that this activity needs dependency injection:
@AndroidEntryPoint class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MyScreen() } } }
Summary of Components
Dependencies: Add Hilt and related dependencies in your
build.gradle
file.Application Class: Annotate your application class with
@HiltAndroidApp
.ViewModel: Annotate with
@HiltViewModel
and inject the repository.Repository: Handle your data operations and use constructor injection.
Hilt Module: Use
@Module
and@Provides
to provide dependencies (e.g., Retrofit).MainActivity and Composables: Use
@AndroidEntryPoint
andhiltViewModel()
to inject dependencies.
Conclusion
Using Hilt for dependency injection in a Kotlin Android Jetpack Compose project with MVVM architecture significantly improves code readability and scalability. Hilt makes it easy to manage dependencies, especially in projects that grow complex over time, by providing seamless injections and simplifying boilerplate setup. Following the steps outlined in this article will help you integrate Hilt into your project effectively, ensuring clean and maintainable architecture.
Ready to start building your next Android project using Hilt and Jetpack Compose? Dive in and simplify your dependency management now!
#Kotlin #Code4Kotlin