'Android Koin DI - Sharing ViewModel with multiple implementations
I have a viewModel like:
abstract class MyViewModel : ViewModel() {
abstract fun onTextUpdated(text: String)
abstract val liveData: LiveData<String>
}
Which has 2 implementations like:
class MyViewModelOne : MyViewModel() {
override fun onTextUpdated(text: String) { // Do stuff }
override val liveData = MutableLiveData<String>()
}
class MyViewModelTwo : MyViewModel() {
override fun onTextUpdated(text: String) { // Do stuff }
override val liveData = MutableLiveData<String>()
}
Which are each used in their own seperate fragments, let's call them FragmentOne and FragmentTwo for the sake of demonstration.
FragmentOne and FragmentTwo both share the requirement to ask the user to enter some text via a dialog added to the host activity when the user taps a "Add Note" button. Let's call this dialog FragmentThree for the sake of demonstration. The result of this dialog (a string) should be shared with the parent fragment via the onTextUpdated function on either FragmentOne or FragmentTwo respectively, depending upon which route the user took through the app, when the dialog is dismissed.
Obviously, I only want to implement the FragmentThree dialog once, as it will look the same and have the same behaviour for both the FragmentOne and FragmentTwo use cases.
Therefore, I decided in the FragmentThree implementation to make use of Koins by sharedViewModel delegate, to share the viewModel injected in with the parent scope (the activity level). Obviously, because I don't know which implementation of MyViewModel will be there, because either FragmentOne or FragmentTwo could have lead to this point, I am referencing the base abstract class MyViewModel instead, assuming that Koin will be able to resolve this at run time.
However, when I run the code, the app crashes with:
2022-04-12 09:51:52.422 3607-3607/com.example.test E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.test, PID: 3607
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: org.koin.core.error.NoBeanDefFoundException: |- No definition found for class:'com.example.test.MyViewModel'. Check your definitions!
In my Koin module, where I am creating the definitions of what interfaces/abstract classes map to which implementations, I have correctly setup definitions for both of the implementations of MyViewModel, and the FragmentOne and FragmentTwo code which uses this view model via the by sharedViewModel delegate works fine as I also stipulate a qualifier for each of them, in both the module definitions and the fragments themselves, like so:
val appModule = module {
viewModel<MyViewModel>(
named("myViewModelOne")
) {
MyViewModelOne()
}
viewModel<MyViewModel>(
named("myViewModelTwo")
) {
MyViewModelTwo()
}
}
And then, in FragmentOne and FragmentTwo where the implementations are used, similarly:
class FragmentOne : Fragment() {
private val viewModel by sharedViewModel<MyViewModel>(
named("myViewModelOne")
)
...
}
class FragmentTwo : Fragment() {
private val viewModel by sharedViewModel<MyViewModel>(
named("myViewModelTwo")
)
...
}
And finally, in FragmentThree where I am wanting Koin to determine the implementation dynamically based upon the parent fragments view model implementation:
class FragmentThree : DialogFragment() {
private val viewModel by sharedViewModel<MyViewModel>()
...
}
So, my question is; is there someway I can share the view model from either FragmentOne or FragmentTwo via referencing it's base class in the by sharedViewModel delegate in FragmentThree without also qualifying which implementation to use (because I want it to use whichever implementation is currently active on it's parent fragment).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
