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
GitHub Repository: Android News (Hilt branch)
Branch Diff: Master vs Hilt