avatarVincent Tsen

Summary

The provided context describes the process of converting an Android News app to use Hilt Dependency Injection, focusing on the View Model dependency injection.

Abstract

The author of the provided context follows the steps outlined in a previous article to convert the Android News app to use Hilt Dependency Injection. The initial setup steps include adding Hilt dependencies, using the @HiltAndroidApp annotation in the application class, and adding @AndroidEntryPoint in the activity. To create the MainViewModel, the author uses @HiltViewModel and @Inject constructor, and to create the dependencies, they use @Provides and @Binds. The author also explains how to call the hiltViewModel() composable function to generate all necessary dependencies and remove manual creations in the MainActivity. The context concludes with the author expressing their preference for manual dependency injection over Hilt.

Opinions

  • The author prefers manual dependency injection over Hilt.
  • The author finds it challenging to change the installed module to another component, such as ViewModelComponent or ActivityComponent, and fails to compile.
  • The author expresses their intention to continue exploring Hilt and learning how to fix the issues they encountered.
  • The author provides a link to their recommended ways of creating ViewModel or AndroidViewModel, which involves manual dependency injection.
  • The author provides a link to the source code of the Android News app with Hilt Dependency Injection.
  • The author mentions that they still don't like Hilt and calls themselves "grandpa" for preferring manual dependency injection.
  • The author concludes by mentioning that they still have more to learn about Hilt and that this is their next step.

Convert View Model to Use Hilt Dependency Injection

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? article to convert the Android News app 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:

2. Add @HiltViewModel and @Inject Constructor

In order for Hilt to create MainViewModel, you need to annotate the class with @HiltViewModel. @Inject constructor is also used to tell Hilt how the dependencies can be created.

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

I also use @Inject Constructor on the SqlArticlesRepository.

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 and @Binds. @Provides is used to create ArticlesDatabase and WebService instances.

@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.

@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.

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.

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

MainScreen(homeViewModel, useSystemUIController = true)

with

MainScreen(viewModel = hiltViewModel(), useSystemUIController = true)

The database creation below can also be removed since it has been provided by hilt @Provides above.

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.

@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:

Source Code

Originally published at https://vtsen.hashnode.dev.

AndroidDev
Android App Development
Dependency Injection
Android Apps
Viewmodel
Recommended from ReadMedium