Hilt doesn't support keyed view models. There's a feature request for keyed view models in Compose, but we had to wait until Hilt supports it.
Here's a hacky solution on how to bypass it for now.
You can create a plain view model, which can be used with keys, and pass injections to this view model through Hilt view model:
class SomeInjection @Inject constructor() {
val someValue = 0
}
@HiltViewModel
class InjectionsProvider @Inject constructor(
val someInjection: SomeInjection
): ViewModel() {
}
class SomeViewModel(private val injectionsProvider: InjectionsProvider) : ViewModel() {
val injectedValue get() = injectionsProvider.someInjection.someValue
var storedValue by mutableStateOf("")
private set
fun updateStoredValue(value: String) {
storedValue = value
}
}
@Composable
fun keyedViewModel(key: String) : SomeViewModel {
val injectionsProvider = hiltViewModel<InjectionsProvider>()
return viewModel(
key = key,
factory = object: ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return SomeViewModel(injectionsProvider) as T
}
}
)
}
@Composable
fun TestScreen(
) {
LazyColumn {
items(100) { i ->
val viewModel = keyedViewModel("$i")
Text(viewModel.injectedValue.toString())
TextField(value = viewModel.storedValue, onValueChange = viewModel::updateStoredValue)
}
}
}
UPDATE after Hilt 2.43 release
You can create function like:
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.hilt.navigation.HiltViewModelFactory
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavBackStackEntry
@Composable
inline fun <reified VM : ViewModel> hiltViewModel(key: String): VM {
val viewModelStoreOwner =
if (checkNotNull(LocalViewModelStoreOwner.current) is NavBackStackEntry) {
checkNotNull(LocalViewModelStoreOwner.current) { "ViewModelStoreOwner is null" }
} else null
return viewModel(
key = key,
factory = if (viewModelStoreOwner is NavBackStackEntry) {
HiltViewModelFactory(
LocalContext.current,
viewModelStoreOwner
)
} else null
)
}
and then use it like:
YourComposableWithViewModelArg(
viewModel = hiltViewModel(key = "MyUniqueViewModelKey"),
// ... rest of the arguments
)