Implementing Hilt in a Kotlin Android Jetpack Compose Project with MVVM Architecture

 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

  1. Dependencies: Add Hilt and related dependencies in your build.gradle file.

  2. Application Class: Annotate your application class with @HiltAndroidApp.

  3. ViewModel: Annotate with @HiltViewModel and inject the repository.

  4. Repository: Handle your data operations and use constructor injection.

  5. Hilt Module: Use @Module and @Provides to provide dependencies (e.g., Retrofit).

  6. MainActivity and Composables: Use @AndroidEntryPoint and hiltViewModel() 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

0 comments:

Post a Comment