Hilt Dependency Injection
Hilt is a dependency injection framework built on top of Dagger that helps reduce a lot of boiler plate when injecting dependencies. Hilt can also help reduce the boiler plate when using SavedStateFlow
by scoping an instance of SavedStateFlowHandle
to any ViewModel
that requests it.
Hilt ViewModel
The saved-state-flow-hilt
artifact provides an instance of SavedStateFlowHandle
to the ViewModelComponent
out of the box, so it can be declared in any ViewModel
constructor like so.
@HiltViewModel
class MainViewModel @Inject constructor(
savedStateFlowHandle: SavedStateFlowHandle,
private val newsDataSource: NewsDataSource
) : ViewModel() {
private val query: SavedStateFlow<String> =
savedStateFlowHandle.getSavedStateFlow(viewModelScope, "main-viewmodel-query-key", "")
init {
observeQuery()
}
fun updateQuery(query: String) {
this.query.value = query
}
private fun observeQuery() {
viewModelScope.launch {
query.asStateFlow()
.flatMapLatest { query ->
newsDataSource.fetchQuery(query)
}
.collect { results ->
// TODO update state with latest results
}
}
}
}
The full version of this ViewModel
can be found here.
Grabbing a Reference to @HiltViewModel
Finally grab a reference to the ViewModel
using the by viewmodels { }
delegation function.
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
private val viewModel: MainViewModel by viewModels()
}
Assisted Injection
When using Hilt, it's possible that the @HiltViewModel
annotation cannot be used when a value needs to be injected into the constructor at runtime. For that, there are a couple of extension methods provided to help inject a SavedStateFlowHandle
when using Hilt's assisted injection from a FragmentActivity
or Fragment
.
Assisted Injected ViewModel
class MyAssistedViewModel @AssistedInject constructor(
@Assisted savedStateFlowHandle: SavedStateFlowHandle,
@Assisted id: String
) : ViewModel() {
@AssistedFactory
interface Factory {
fun create(savedStateFlowHandle: SavedStateFlowHandle, id: String): MyAssistedViewModel
}
}
Grab a reference to an Assisted ViewModel
Then in a Fragment
or a FragmentActivity
, the by assistedViewModel
method may be used to get a reference to a assisted injected ViewModel
as this method provides you an instance of a SavedStateFlowHandle
. There is also a method for fragments to get a ViewModel
scoped to its FragmentActivity
if using the by assistedActivityViewModel {}
method.
@AndroidEntryPoint
class AssistedFragment : Fragment() {
@Inject
lateinit var factory: MyAssistedViewModel.Factory
private val viewModel: MyAssistedViewModel by assistedViewModel { savedStateFlowHandle ->
factory.create(savedStateFlowHandle, arguments?.getString("some-argument-key")!!)
}
}