Now with the new support lib 27.1.0 both Fragment
and FragmentActivity
implement ViewModelStoreOwner
so it makes more sense to just add an extension function on `ViewModelStoreOwner` itself:
inline fun <reified T: ViewModel> ViewModelStoreOwner.getViewModel(crossinline initializer: () -> T): T {
val viewModelClass = T::class.java
val factory = object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return when {
modelClass.isAssignableFrom(viewModelClass) -> initializer.invoke() as T
else -> throw IllegalArgumentException("Unknown ViewModel class")
}
}
}
return ViewModelProvider(this, factory).get(viewModelClass)
}
To retrieve a vew model instance:
// viewModelStoreOwner can be any Fragment or FragmentActivity
viewModel = viewModelStoreOwner.getViewModel {
SearchViewModel(param1, param2, ...)
}
Passing in an initialization block means new viewModel
instance will only be created if factory thinks it’s necessary i.e. no new instance is created after rotation just to get access to the factory. I think this is a slight advantage over extending on T: ViewModel
in which case you always need an instance of viewModel
to access the factory.
And there’s no need to interact with ViewModelFactory
with this approach.
Keen to know your thoughts :)