Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I manage lifecycle owner, injecting viewModel with Koin?

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 it's Fragments: https://insert-koin.io/docs/1.0/documentation/koin-android/index.html

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

like image 591
Anton Shinkaretsky Avatar asked Dec 23 '18 08:12

Anton Shinkaretsky


3 Answers

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

like image 63
Chenhe Avatar answered Sep 29 '22 20:09

Chenhe


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)
like image 27
Krasavello13 Avatar answered Sep 29 '22 20:09

Krasavello13


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)

like image 42
Wirling Avatar answered Sep 29 '22 21:09

Wirling