Convert View Model to Use Hilt Dependency Injection
Tags: android, beginners, kotlin, jetpackcompose
Published: 2022-08-06 00:24:50

**Here are the steps I did and my key learnings to convert my Android News app to use hilt dependency injection**

So I followed the steps in [How to Implement Hilt in Android App?](https://vtsen.hashnode.dev/how-to-implement-hilt-in-android-app) article to convert the [Android News app](https://vtsen.hashnode.dev/simple-rss-feed-reader-jetpack-compose) to use Hilt Dependency Injection. The difference in previous article is it doesn't cover the View Model dependency injection.

## 1. Add Dependencies and `@HiltAndroidApp`
The initial setup steps are exactly the same as the following:

- [Setup Hilt Dependencies](https://vtsen.hashnode.dev/how-to-implement-hilt-in-android-app#heading-1-setup-hilt-dependencies)
- [Add @HiltAndroidApp in your application class](https://vtsen.hashnode.dev/how-to-implement-hilt-in-android-app#heading-2-add-hiltandroidapp-in-your-application-class)
- [Add @AndroidEntryPoint in your activity](https://vtsen.hashnode.dev/how-to-implement-hilt-in-android-app#heading-3-add-androidentrypoint-in-your-activity-and-fragment)

## 2. Add `@HiltViewModel` and `@Inject Constructor`

In order for Hilt to create `MainViewModel`, you need to annotate the class with `@HiltViewModel`. [`@Inject constructor`](https://vtsen.hashnode.dev/how-to-implement-hilt-in-android-app#heading-5-add-inject-constructor-to-tell-hilt-how-to-provide-dependencies) is also used to tell Hilt how the dependencies can be created.

```kotlin
@HiltViewModel
class MainViewModel
    @Inject constructor(
        private val repository: ArticlesRepository,
    ) : ViewModel() {
    ...
}
```

I also use `@Inject Constructor` on the `SqlArticlesRepository`.
```kotlin
class SqlArticlesRepository @Inject constructor(
    private val database: ArticlesDatabase,
    private val webService: WebService,
) : ArticlesRepository {
   ...
}
```

## 3. Add `@Provides` and `@Binds`

To create the dependencies, we use either [@Provides](https://vtsen.hashnode.dev/how-to-implement-hilt-in-android-app#heading-8-inject-instances-with-provides) and [@Binds](https://vtsen.hashnode.dev/how-to-implement-hilt-in-android-app#heading-9-inject-interface-instances-with-binds). `@Provides` is used to create `ArticlesDatabase` and `WebService` instances.

```kotlin
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {

    @Provides
    @Singleton
    fun provideDatabase(@ApplicationContext appContext: Context): ArticlesDatabase {

        return Room.databaseBuilder(
            appContext,
            ArticlesDatabase::class.java,
            "articles.db",
        )
            .fallbackToDestructiveMigration()
            .build()
    }
}

@Module
@InstallIn(SingletonComponent::class)
object WebServiceModule {

    @Provides
    @Singleton
    fun provideWebService(): WebService {
        return WebService()
    }
}
```

`@Binds` is used to create the implementation of `ArticlesRepository` interface.

```kotlin
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {

    @Binds
    @Singleton
    abstract fun bindArticlesRepository(impl: SqlArticlesRepository): ArticlesRepository
}
```

## 4. Call `hiltViewModel()` Composable
Now it is done! All manual creations below in `MainActivity` can be removed.
```kotlin
private val repository by lazy {
    SqlArticlesRepository(
        ArticlesDatabase.getInstance(application),
        WebService(),
    )
}

private val homeViewModel by viewModels<MainViewModel> {
    MainViewModelFactory(repository)
}
```

> **[Updated - 16 Oct, 2022]:** To use `hiltViewModel()`, you need to add the following dependency.

```kotlin
implementation 'androidx.hilt:hilt-navigation-compose:1.0.0'
```

The `MainViewModel` creation can be done by calling the `hiltViewModel()` composable function, which generates all the necessary dependencies.

For example, replace this `MainScreen` composable function
```kotlin
MainScreen(homeViewModel, useSystemUIController = true)
```
with
```kotlin
MainScreen(viewModel = hiltViewModel(), useSystemUIController = true)
```
The database creation below can also be removed since it has been provided by hilt `@Provides` above.
```kotlin
companion object {
    @Volatile
    private lateinit var instance: ArticlesDatabase

    fun getInstance(context: Context): ArticlesDatabase {
        synchronized(this) {
            if (!::instance.isInitialized) {
                instance = Room.databaseBuilder(
                    context.applicationContext,
                    ArticlesDatabase::class.java,
                    "articles.db")
                    .fallbackToDestructiveMigration()
                    .build()
            }

            return instance
        }
    }
}
```

This `MainViewModelFactory` can also be removed since this has been taken care by `@HiltViewModel`.
```kotlin
@Suppress("UNCHECKED_CAST")
class MainViewModelFactory(private val repository: ArticlesRepository)
    : ViewModelProvider.NewInstanceFactory() {

    override fun <T : ViewModel> create(modelClass: Class<T>): T {

        if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
            return MainViewModel(repository) as T
        }

        throw IllegalArgumentException("Unknown ViewModel class")
    }
}
```

## Conclusion
All my installed Hilt modules are in `SingletonComponent` scope. If I change my installed module to another component, for example `ViewModelComponent` or `ActivityComponent`, it fails to compile, and I don't know how to fix it. I guess that is my next step to play around with this `Hilt`. 

Yes, I still don't like `Hilt`. Call me grandpa, but I still prefer manual dependency injection like this one:

- [Recommended Ways To Create ViewModel or AndroidViewModel](https://vtsen.hashnode.dev/recommended-ways-to-create-viewmodel-or-androidviewmodel)

## Source Code
- GitHub Repository: [Android News](https://github.com/vinchamp77/AndroidNews/tree/master_org_hilt) (Hilt branch)
- Branch Diff: [Master vs Hilt](https://github.com/vinchamp77/AndroidNews/compare/129e75036178fa2427e7283a605ada6e7fa27325..a23b2dfc36447be82339fb26d9a3e1a36108fb4a) 

---

*Originally published at [https://vtsen.hashnode.dev](https://vtsen.hashnode.dev/convert-view-model-to-use-hilt-dependency-injection)*.