Let's say I have a module for my fragment.
scope(named<MyFragment>()) {
viewModel {
MyFragmentVM(
get(),
get(),
get(),
get()
)
}
}
From MyFragmentVM I open a dialog fragment, where I pass MyFragment's scopeId. From my dialog on some action I would like to call my MyFragmentVM's method.
Is there any way to get the MyFragmentVM?
I can see some methods, but they require ViewModelParameters and so on.
I need smth that does not require anything else but scope/scopeId.
The recommendation is your host activity will have a view model. Then fragments can use the sharedViewModel.
Koin already does that for you. Don't create your own scope.
https://doc.insert-koin.io/#/koin-android/viewmodel?id=shared-viewmodel
`class WeatherActivity : AppCompatActivity() {
/*
* Declare WeatherViewModel with Koin and allow constructor dependency injection
*/
private val weatherViewModel by viewModel<WeatherViewModel>()
}
class WeatherHeaderFragment : Fragment() {
/*
* Declare shared WeatherViewModel with WeatherActivity
*/
private val weatherViewModel by sharedViewModel<WeatherViewModel>()
}
class WeatherListFragment : Fragment() {
/*
* Declare shared WeatherViewModel with WeatherActivity
*/
private val weatherViewModel by sharedViewModel<WeatherViewModel>()
}
`
Yeah, I know. But a shared viewmodel is tied to an activity's lifecycle, so it won't be destroyed with fragment. Plus in my case I have some fragment dependent logic inside its viewmodel, that wouldn't be nice to separate it and put just 1 call to a shared view model. In Dagger2 I can get a parent Component and inject fragment viewmodel inside my dialog, so now I try Koin and wanna find the way to do the same.
You need only declare sharedViewModel inside fragments.
Don't create your own scope.
class MyFragment : Fragment() {
private val myViewModel by sharedViewModel<MyViewModel>()
}
The extension sharedViewModel call getSharedViewModel that uses requireActivity() internally and already "bind" the scope to activity.
inline fun <reified T : ViewModel> Fragment.sharedViewModel(
qualifier: Qualifier? = null,
noinline parameters: ParametersDefinition? = null
): Lazy<T> =
lazy { getSharedViewModel<T>(qualifier, parameters) }
fun <T : ViewModel> Fragment.getSharedViewModel(
clazz: KClass<T>,
qualifier: Qualifier? = null,
parameters: ParametersDefinition? = null
): T {
return requireActivity().getViewModel( // Here
clazz,
qualifier,
parameters
)
}
Therefore, you don't need to declare the viewModel within the activity if you do not use it .
You need only declare
sharedViewModelinside fragments.Don't create your own scope.
class MyFragment : Fragment() { private val myViewModel by sharedViewModel<MyViewModel>() }The extension
sharedViewModelcallgetSharedViewModelthat usesrequireActivity()internally and already "bind" the scope to activity.inline fun <reified T : ViewModel> Fragment.sharedViewModel( qualifier: Qualifier? = null, noinline parameters: ParametersDefinition? = null ): Lazy<T> = lazy { getSharedViewModel<T>(qualifier, parameters) } fun <T : ViewModel> Fragment.getSharedViewModel( clazz: KClass<T>, qualifier: Qualifier? = null, parameters: ParametersDefinition? = null ): T { return requireActivity().getViewModel( // Here clazz, qualifier, parameters ) }Therefore, you don't need to declare the
viewModelwithin the activity if you do not use it .
will that viewmodel be destroyed with fragment? I mean if I leave the fragment with declared sharedviewmodel will it still be alive?
You need only declare
sharedViewModelinside fragments.Don't create your own scope.
class MyFragment : Fragment() { private val myViewModel by sharedViewModel<MyViewModel>() }The extension
sharedViewModelcallgetSharedViewModelthat usesrequireActivity()internally and already "bind" the scope to activity.inline fun <reified T : ViewModel> Fragment.sharedViewModel( qualifier: Qualifier? = null, noinline parameters: ParametersDefinition? = null ): Lazy<T> = lazy { getSharedViewModel<T>(qualifier, parameters) } fun <T : ViewModel> Fragment.getSharedViewModel( clazz: KClass<T>, qualifier: Qualifier? = null, parameters: ParametersDefinition? = null ): T { return requireActivity().getViewModel( // Here clazz, qualifier, parameters ) }Therefore, you don't need to declare the
viewModelwithin the activity if you do not use it .will that viewmodel be destroyed with fragment? I mean if I leave the fragment with declared sharedviewmodel will it still be alive?
You need only declare
sharedViewModelinside fragments.Don't create your own scope.
class MyFragment : Fragment() { private val myViewModel by sharedViewModel<MyViewModel>() }The extension
sharedViewModelcallgetSharedViewModelthat usesrequireActivity()internally and already "bind" the scope to activity.inline fun <reified T : ViewModel> Fragment.sharedViewModel( qualifier: Qualifier? = null, noinline parameters: ParametersDefinition? = null ): Lazy<T> = lazy { getSharedViewModel<T>(qualifier, parameters) } fun <T : ViewModel> Fragment.getSharedViewModel( clazz: KClass<T>, qualifier: Qualifier? = null, parameters: ParametersDefinition? = null ): T { return requireActivity().getViewModel( // Here clazz, qualifier, parameters ) }Therefore, you don't need to declare the
viewModelwithin the activity if you do not use it .will that viewmodel be destroyed with fragment? I mean if I leave the fragment with declared sharedviewmodel will it still be alive?
The lifecycleOwner in this case is the Activity. The viewModel will be destroyed with the Activity and not with fragment.
So here we're back again.
As I told before - I don't need a sharedviewmodel for the case described above. I need to get my fragment's NOT shared view model from a dialog. In case of shared vm it will outlive fragment, what's not good in my case.
So as I can see there's no way to get NOT shared vm from a child fragment event if you have the scopeId.
So here we're back again.
As I told before - I don't need a sharedviewmodel for the case described above. I need to get my fragment's NOT shared view model from a dialog. In case of shared vm it will outlive fragment, what's not good in my case.
So as I can see there's no way to get NOT shared vm from a child fragment event if you have the scopeId.
For your case, I think you could use getParentFragment from DialogFragment as a LifecycleOwner and get viewModel from that. Maybe this...
// on dialog
val myViewModel: MyViewModel = getParentFragment().getViewModel(...) // using named here
What do you think?
yeah, guess that's the only way
You can try to use this solution:
private val viewModel by lazy {
requireParentFragment().getViewModel<MyViewModel>()
}
Or if you are using Navigation component from Google:
inline fun <reified VM : ViewModel> Fragment.sharedGraphViewModel(
@IdRes navGraphId: Int,
qualifier: Qualifier? = null,
noinline parameters: ParametersDefinition? = null
) = lazy {
val store = findNavController().getViewModelStoreOwner(navGraphId).viewModelStore
getKoin().getViewModel(ViewModelParameter(VM::class, qualifier, parameters, null, store, null))
}
For correct work you have to put your fragments to the nested navigation
Most helpful comment
So here we're back again.
As I told before - I don't need a sharedviewmodel for the case described above. I need to get my fragment's NOT shared view model from a dialog. In case of shared vm it will outlive fragment, what's not good in my case.
So as I can see there's no way to get NOT shared vm from a child fragment event if you have the scopeId.