1

I’m declaring a ViewModel with SavedStateHandle as parameter in koin modules

  1. in koin modules
viewModel { (handle: SavedStateHandle) -> CacheProvider(handle) }

viewModel { SomeFragmentUsedViewModel(get()) }
  1. And initiate it in Activity
lateinit var cacheProvider: CacheProvider

  1. Reuse it in SomeFragment
private val viewModel: SomeFragmentUsedViewModel by inject()

private val cacheProvider: CacheProvider by sharedViewModel()
  1. When navigating into SomeFragment, app crashed when accessing to both ViewModel:
2020-04-30 22:04:04.858 26677-26677/com.ncbportal.sit E/[Koin]: Instance creation error : could not create instance for [Factory:'com.ncb.common.viewmodel.CacheProvider']: org.koin.core.error.NoParameterFoundException: Can't get parameter value #0 from org.koin.core.parameter.DefinitionParameters@a37a822
        org.koin.core.parameter.DefinitionParameters.elementAt(DefinitionParameters.kt:32)
        org.koin.core.parameter.DefinitionParameters.component1(DefinitionParameters.kt:34)
        com.ncbportal.di.ViewModelModuleKt$viewModelModule$1$77.invoke(Unknown Source:11)
        com.ncbportal.di.ViewModelModuleKt$viewModelModule$1$77.invoke(Unknown Source:4)
        org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)
        org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:36)
        org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:87)
        org.koin.core.scope.Scope.resolveInstance(Scope.kt:214)
        org.koin.core.scope.Scope.get(Scope.kt:181)
        com.ncbportal.di.ViewModelModuleKt$viewModelModule$1$76.invoke(ViewModelModule.kt:117)
        com.ncbportal.di.ViewModelModuleKt$viewModelModule$1$76.invoke(Unknown Source:4)
        org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)
        org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:36)
        org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:87)
        org.koin.core.scope.Scope.resolveInstance(Scope.kt:214)
        org.koin.core.scope.Scope.get(Scope.kt:181)
        com.ncbportal.deposit.fragment.ApplyTermDepositFragment$$special$$inlined$inject$1.invoke(ComponentCallbackExt.kt:51)
        kotlin.UnsafeLazyImpl.getValue(Lazy.kt:81)


2020-04-30 22:04:04.861 26677-26677/com.ncbportal.sit E/[Koin]: Instance creation error : could not create instance for [Factory:'com.ncbportal.deposit.viewmodel.ApplyTermDepositViewModel']: org.koin.core.error.InstanceCreationException: Could not create instance for [Factory:'com.ncb.common.viewmodel.CacheProvider']
        org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:59)
        org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:36)
        org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:87)
        org.koin.core.scope.Scope.resolveInstance(Scope.kt:214)
        org.koin.core.scope.Scope.get(Scope.kt:181)
        com.ncbportal.di.ViewModelModuleKt$viewModelModule$1$76.invoke(ViewModelModule.kt:117)
        com.ncbportal.di.ViewModelModuleKt$viewModelModule$1$76.invoke(Unknown Source:4)
        org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)
        org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:36)
        org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:87)
        org.koin.core.scope.Scope.resolveInstance(Scope.kt:214)
        org.koin.core.scope.Scope.get(Scope.kt:181)
        com.nextbank.ncbportal.deposit.fragment.ApplyTermDepositFragment$$special$$inlined$inject$1.invoke(ComponentCallbackExt.kt:51)
        kotlin.UnsafeLazyImpl.getValue(Lazy.kt:81)

Search all around koin repo issues it seems not definite way of creating a app-wise ViewModel (CacheProvider in my case) for all fragments and ViewModel to access.

Does anyone have any clue about this?

Robert
  • 1,660
  • 22
  • 39

2 Answers2

1

According to this post, there will be new version of koin providing some extension function to make life easier. Follow the lead after adding those extension functions as workaround, it works for now.

But the major issue is that I try to put that app-wise shared CacheProvider as parameter into SomeFragmentUsedViewModel. This seems impossible for injection. So the data flow have to be:

  1. in koin module
viewModel { (handle: SavedStateHandle) -> CacheProvider(handle) }

viewModel { SomeFragmentUsedViewModel() }

  1. In activity
private val cacheProvider: CacheProvider by stateViewModel {
        parametersOf(
            SavedStateHandle()
        )
    }
  1. Reuse it in SomeFragment
private val viewModel: SomeFragmentUsedViewModel by inject()

private val cacheProvider: CacheProvider by stateSharedViewModel()

  1. Feed data from cacheProvider into viewModel. So fragment works as bridge between two ViewModels.
cacheProvider.data?.let { safeData ->
  viewModel.initDataWith(safeData)

}
Robert
  • 1,660
  • 22
  • 39
0

It seems you are trying to pass viewmodel into another viewmodel? Not good (what kind of app wide view is it going to serve?). Your CacheProvider should be something different than view model (app wide singletone cache repo?).

I'd suggest you to try it this way: Koin sharedViewModel with SavedStateHandle

At the end of the day your SomeFragmentUsedViewModel should manage state saving/restoring, not CacheProvider. Latter one should likely be what it's called: cache provider, without access to view state saving/restoring mechanism.

It is somewhat important to tell the above works with koin ver 2.1.5.

ror
  • 3,295
  • 1
  • 19
  • 27
  • Thanks for replying! Yes, CacheProvide is supposed to be an app-wise cache. And I'm trying to have a app-wise cache by using shareViewModel with SavedStateHandle. The use case is an Activity holding data (via shareViewModel) for its children fragments (across at least 10 fragments). I found your post and tried already. Still experimenting. – Robert May 05 '20 at 06:31