Is your feature request related to a problem? Please describe.
I maintain a little library that adds ViewModel support from AAC to Conductor, and recently got this question: https://github.com/miquelbeltran/conductor-viewmodel/issues/1
Have you used Koin at all to inject your ViewModels?
I tried and found an issue: Koin relies on the parent Activity or the Fragment to obtain the ViewModelProvider. However, my Controller class (a replacement for Fragments by Conductor) also is a ViewModelProvider.
This is the method/line that causes the problem: https://github.com/InsertKoinIO/koin/blob/f71200780dd2018e5fdd6292b0a02772396117bd/koin-android-architecture/src/main/java/org/koin/android/architecture/ext/LifecycleOwnerExt.kt#L166
Describe the solution you'd like
A solution would be having an optional paramater in viewModel() and getViewModel(), being able to pass the ViewModelProvider by parameter.
So I can call: val myViewModel by viewModel(viewModelProvider = getMyViewModelProvider())
And the getViewModelByClass will use that provided ViewModelProvider instead.
Describe alternatives you've considered
The alternative is to not to use the ViewModel Koin extension and inject the ViewModelFactories instead.
Target Koin project
this is an improvement for koin-android-architecture
Thanks for considering! I would be very happy to implement it and provide a PR with the solution if you think it is worth it. I am happy user of Koin and as well Conductor, and would like to see them working together. :-)
Hello @arnaudgiuliani, any news about this feature? Thank you!
Yeah, good to ping it.
included in 2.0
wow! thank you!
@arnaudgiuliani one question, could you provide an information how to use the feature in 2.0.0?
sorry, false alert.
ViewModelProvider is generated by Koin: https://github.com/InsertKoinIO/koin/blob/master/koin-projects/koin-android-viewmodel/src/main/java/org/koin/android/viewmodel/ViewModelResolution.kt#L33
The need above is to replace this part then?
Ah, as I understand now, we can provide the ViewModelParameters.from as any custom ViewModelProvider we would like to use.
So we can do now:
val myViewModel: MyViewModel by viewModel(ViewModelParameters(from = { myCustomViewModelProvider })) // more or less
correct?
on Fragment yes. On Activity, you have to dig with more inner API: fun <T : ViewModel> LifecycleOwner.resolveViewModelInstance(parameters: ViewModelParameters<T>)
In ViewModelParameters you can specify the ViewModelStoreOwnerDefinition which is a function to define ViewModelStoreOwner
Should it currently work?
I got this error:
"Feature1Controller@3ae75b - Is not a FragmentActivity nor a Fragment neither a valid ViewModelStoreOwner"
class Feature1Controller: BaseController() {
override val vm: Feature1ViewModel by viewModel { parametersOf(ViewModelParameters(owner = this, from = { this }, clazz = Feature1Controller::class)) }
...
}
abstract class BaseController(): Controller(), LifecycleOwner, ViewModelStoreOwner, KoinComponent {
abstract val vm: BaseViewModel
...
}
class Feature1ViewModel: BaseViewModel() {
...
}
Documentation will be updated.
@arnaudgiuliani in the mean time, could you provide a quick snippet here on how it should work? :)
ViewModel API has been refined to make this API better.
ViewModelParameter is now clearly simpler to use:
class ViewModelParameter<T : Any>(
val clazz: KClass<T>,
val qualifier: Qualifier? = null,
val parameters: ParametersDefinition? = null,
val viewModelStore: ViewModelStore
)
The API offers a simple way to access from "assisted" params to full open:
inline fun <reified T : ViewModel> Scope.viewModel(
owner: LifecycleOwner,
qualifier: Qualifier? = null,
noinline parameters: ParametersDefinition? = null
): Lazy<T>
inline fun <reified T : ViewModel> Scope.getViewModel(
owner: LifecycleOwner,
qualifier: Qualifier? = null,
noinline parameters: ParametersDefinition? = null
): T
fun <T : ViewModel> Scope.getViewModel(
owner: LifecycleOwner,
clazz: KClass<T>,
qualifier: Qualifier? = null,
parameters: ParametersDefinition? = null
): T
fun <T : ViewModel> Scope.getViewModel(viewModelParameters: ViewModelParameter<T>): T
For AndroidX, we add the SavedStateRegistryOwner property as below:
class ViewModelParameter<T : Any>(
val clazz: KClass<T>,
val qualifier: Qualifier? = null,
val parameters: ParametersDefinition? = null,
val viewModelStore: ViewModelStore,
val stateRegistryOwner: SavedStateRegistryOwner? = null
)
This will allow to use the Koin AbstractSavedStateViewModelFactory directly.
Hi, is there a working example I can take a look into? Thanks
Most helpful comment
included in 2.0