Håkon Pettersen
01/10/2023, 6:35 PMPablichjenkov
01/10/2023, 7:45 PMmattinger
01/11/2023, 4:33 AMinterface ViewModelFactoryCreator {
fun create(owner: ViewModelStoreOwner): ViewModelProvider.Factory
}
class MyViewModel: ViewModel()
@Composable
fun MyComposable(viewModelFactoryCreator: ViewModelFactoryCreator) {
val viewModel: MyViewModel = viewModel(
factory = viewModelFactoryCreator.create(LocalViewModelStoreOwner.current!!)
)
}
I provide an implementation of the above interface in my dagger graph, and inject it to the activity, and just pass it along either as a parameter, or through a composition local (I prefer the former).
If you want a view model scoped to your compose destination, the "NavBackStackEntry" implements ViewModelStoreOwner.mattinger
01/11/2023, 4:40 AMinterface ViewModelFactoryCreator {
fun create(owner: SavedStateRegistryOwner): ViewModelProvider.Factory
}
class DefaultViewModelFactoryCreator: ViewModelFactoryCreator {
override fun create(owner: SavedStateRegistryOwner): ViewModelProvider.Factory {
return object: AbstractSavedStateViewModelFactory(owner, null) {
override fun <T : ViewModel?> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
): T {
return when (modelClass) {
MyViewModel::class.java -> MyViewModel(handle)
else -> throw IllegalArgumentException("unknown view model $modelClass")
} as T
}
}
}
}
class MyViewModel(val savedStateHandle: SavedStateHandle): ViewModel()
@Composable
fun MyComposable(viewModelFactoryCreator: ViewModelFactoryCreator) {
val viewModel: MyViewModel = viewModel(
factory = viewModelFactoryCreator.create(LocalSavedStateRegistryOwner.current)
)
}
You can then create the implementation in your dagger graph with a when clause or use @IntoSet or some other mechanism if you want to be a bit more modular.
This lets you hide all the dependencies that are needed to create the individual view models within your dagger graph, so that they are not leaked to the UI layer.