7

I have single Activity application.

I want to bind viewModel to the parent fragment lifecycle (FlowFragmentLogin), and share it with child fragments (CellFragment, InfoFragment, etc). So that when I move from FlowFragmentLogin to FlowFragmentMain, viewModel onCleared() was called.

But the only way I found is to share viewModel between Activity, and its Fragments: https://insert-koin.io/docs/1.0/documentation/koin-android/index.html

And no control over lifecycle-owners. Which is unacceptable for me, at least because this viewModel will live until the application's death.

Jason Aller
  • 3,541
  • 28
  • 38
  • 38

3 Answers3

4

Since Navigation 2.1.0-alpha02:

You can now create ViewModels that are scoped at a navigation graph level via the by navGraphViewModels() property delegate for Kotlin users or by using the getViewModelStore() API added to NavController.

You can find the change log here and the document.

Unfortunately Koin can not support the feature since viewModel() or sharedViewModel() was bond to Activity. But support for nav has already planned in 2.1.x and you can track here.


For now here's my solution:

  1. Use navGraphViewModels() instead of viewModel() in Koin.
class DetailFr : Fragment() {
    private val vm: DetailViewModel by navGraphViewModels(R.id.main_nav_graph)
}
  1. Make ViwModel implements KoinComponent so that we can use by inject() instead of inject by constructor.
class DetailViewModel : ViewModel(), KoinComponent {

    private val repo: DetailRepository by inject()
    // othetr objects you need
}

Hopefully this helps

Chenhe
  • 924
  • 8
  • 19
4

You can do it by using new version of Koin(2.1.0) and some magic :)

All you need is add this extension function:

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))
}

And now you can simple get your ViewModel from nested graph by:

private val viewModel: MyViewModel by sharedGraphViewModel(R.id.my_graph)
Krasavello13
  • 313
  • 5
  • 9
2

In Koin version 3.1.3 there is a new extension function koinNavGraphViewModel.

just add the following dependency

implementation "io.insert-koin:koin-androidx-navigation:$koin_version"

It can be used like this

private val viewModel: MyViewModel by koinNavGraphViewModel(R.id.my_graph)

Wirling
  • 4,810
  • 3
  • 48
  • 78