I have this base class for view model factory :
class BaseViewModelFactory<T>(val creator: () -> T) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return creator() as T
}
}
I want to convert it to delegation property something like this..
inline fun <reified T : ViewModel> ViewModel.lazyWithParams(noinline provider: () -> T): ReadOnlyProperty<ViewModel, T> {
return ...
}
If not possible maybe as extension function example...
Thanks!
CodePudding user response:
Here's a way to do that:
class LazyViewModelDelegate<T: ViewModel>(
private val viewModelClass: Class<T>,
private val viewModelProducer: () -> T) {
lateinit var provider: ViewModelProvider
operator fun getValue(owner: ViewModelStoreOwner, property: KProperty<*>): T {
if(!::provider.isInitialized) {
provider = ViewModelProvider(owner, object : ViewModelProvider.Factory {
//Unchecked cast because we only request a ViewModel of type T from this provider
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return viewModelProducer.invoke() as T
}
})
}
return provider.get(viewModelClass)
}
}
inline fun <reified T: ViewModel> ViewModelStoreOwner.viewModelFactory(noinline factory: () -> T) =
LazyViewModelDelegate(T::class.java, factory)
To use, put in your activity e.g.
private val viewModel by viewModelFactory {
LoginActivityViewModel()
}
Though perhaps not the cleanest approach, it's possible to add parameters to the constructor of the viewmodel, the viewModel will be instantiated lazily when you first access it.