I'm using new Koin version 2.2.1 and I'm getting runtime error in viewmodel where i'm using SavedStateHandle
In previous version 2.1.6 all was fine. I used savedStateViewModel, now i'm getting crash after migration
all I did acording to article, maybe something are missed there?
https://doc.insert-koin.io/#/koin-android/viewmodel?id=viewmodel-and-state-bundle
Caused by: org.koin.core.error.NoBeanDefFoundException: No definition found for class:'androidx.lifecycle.SavedStateHandle'. Check your definitions!
at org.koin.core.scope.Scope.throwDefinitionNotFound(Scope.kt:282)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:251)
at org.koin.core.scope.Scope.get(Scope.kt:204)
at com.grument.laika.di.DiManager$module$1$19.invoke(DiManager.kt:76)
at com.grument.laika.di.DiManager$module$1$19.invoke(DiManager.kt:35)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:36)聽
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:103)聽
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:236)聽
at org.koin.core.scope.Scope.get(Scope.kt:204)聽
at org.koin.androidx.viewmodel.factory.StateViewModelFactory.create(StateViewModelFactory.kt:21)聽
at androidx.lifecycle.AbstractSavedStateViewModelFactory.create(AbstractSavedStateViewModelFactory.java:69)聽
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)聽
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)聽
at org.koin.androidx.viewmodel.ViewModelResolverKt.get(ViewModelResolver.kt:23)聽
at org.koin.androidx.viewmodel.ViewModelResolverKt.resolveInstance(ViewModelResolver.kt:12)聽
at org.koin.androidx.viewmodel.scope.ScopeExtKt.getViewModel(ScopeExt.kt:86)聽
at org.koin.androidx.viewmodel.scope.ScopeExtKt.getViewModel(ScopeExt.kt:72)聽
at org.koin.androidx.viewmodel.koin.KoinExtKt.getViewModel(KoinExt.kt:41)聽
at org.koin.androidx.viewmodel.ext.android.FragmentExtKt.getViewModel(FragmentExt.kt:71)聽
at com.grument.laika.view.transfer.StyleTransferFragment$$special$$inlined$viewModel$2.invoke(FragmentExt.kt:73)聽
at com.grument.laika.view.transfer.StyleTransferFragment$$special$$inlined$viewModel$2.invoke(Unknown Source:0)聽
at kotlin.UnsafeLazyImpl.getValue(Lazy.kt:81)聽
at com.grument.laika.view.transfer.StyleTransferFragment.getViewModel(Unknown Source:2)聽
at com.grument.laika.view.transfer.StyleTransferFragment.initObservers(StyleTransferFragment.kt:101)聽
at com.grument.laika.view.transfer.StyleTransferFragment.onViewCreated(StyleTransferFragment.kt:42)聽
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:332)聽
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1199)聽
at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2236)聽
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2009)聽
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1965)聽
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1861)聽
at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)聽
at android.os.Handler.handleCallback(Handler.java:938)聽
at android.os.Handler.dispatchMessage(Handler.java:99)聽
at android.os.Looper.loop(Looper.java:223)聽
at android.app.ActivityThread.main(ActivityThread.java:7656)聽
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)聽
in module
viewModel { (image: File) -> StyleTransferViewModel(context = androidContext(), repository = get(), modelManager = get(), state = get(), image = image) }
the class where i'm injecting
class StyleTransferViewModel(private val context: Context,
private val repository: Repository,
private val modelManager: ModelManager,
state: SavedStateHandle,
image: File) : CommonViewModel(repository)
in fragment
private val viewModel: StyleTransferViewModel by viewModel{ parametersOf(args.image) }
Koin project used and used version (please complete the following information):
Any help apreciated
Hi, already resolved this issue, but with weird solution.
Before in module was like this, all values in ViewModel constructor was passed by name
viewModel { (image: File) -> StyleTransferViewModel(context = androidContext(), repository = get(), modelManager = get(), state = get(), image = image) }
Now I changed by order
viewModel { (image: File) -> StyleTransferViewModel(androidContext(), get(), get(), get(), image) }
And all works well. Not sure what caused this issue, this all really very weird.
same here with @OleksandrGrument
can be a problem with new default ViewModel factory 馃
it's curious that it's looking for default state bundle
.NoBeanDefFoundException: No definition found for class:'androidx.lifecycle.SavedStateHandle'
The same problem happened to me using version 2.2.2. The only way I could make it work is by changing the ViewModel constructor params order to have the SavedStateHandle as the first parameter.
Obviously it took me some hours to figure it out 馃槺
I also get the Caused by: org.koin.core.error.NoBeanDefFoundException: No definition found for class:'androidx.lifecycle.SavedStateHandle'. Check your definitions!. In my case setting the handle as first parameter does not solve it.
And passing the parameters by name or by position does not fix it either.
I have also noticed I am not able to add the state parameter when calling by viewModel(state = { Bundle() }). The viewModel method does not accept a state variable and I was not able to find an import that accepts it. I am on 2.2.2.
@jsaumellbasetis I'm using import org.koin.androidx.viewmodel.scope.emptyState as it is done in the example here.
Ok sorry, I got it. I had spent several hours on this, and half an hour after writing I see that I did not have the androidx-fragment koin library, and I had the android-viewmodel instead of androix-viewmodel.
With these changes it works now.
Similar problem if the savedStateHandle parameter is not the first.
Weird.
val koinVersion = "2.2.2"
implementation("org.koin:koin-androidx-viewmodel:$koinVersion")
implementation("org.koin:koin-androidx-fragment:$koinVersion")
implementation("org.koin:koin-androidx-ext:$koinVersion")
I saw in other issues messages about stateViewModel/sharedStateViewModel is it deprecated or i'm looking not at the right place?
I have sharedGraphViewModel and can't combine it with SavedStateHandle.
ViewModel
class CheckoutViewModel(
val handle: SavedStateHandle,
other staff
) : ViewModel()
viewModel { CheckoutViewModel(get(),....) }
Delegate to share viewmodel. It seems I need something like getKoin().getStateViewModel but it's not in the library anymore.
inline fun <reified VM : ViewModel> Fragment.sharedGraphViewModel(
@IdRes navGraphId: Int,
qualifier: Qualifier? = null,
noinline initialState: BundleDefinition? = null,
noinline parameters: ParametersDefinition? = null,
) = lazy(LazyThreadSafetyMode.NONE) {
getKoin().getViewModel(
qualifier = qualifier,
state = initialState,
owner = { ViewModelOwner.from(findNavController().getViewModelStoreOwner(navGraphId)) },
clazz = VM::class,
parameters = parameters
)
}
And usage
private val viewModel by sharedGraphViewModel<CheckoutViewModel>(R.id.navigationCheckout) {
parametersOf(args.orderId, args.order)
}
Any thoughts how to combine sharedGraphViewModel and SavedStateHandle?
It seems I figurre it out. Please have a look at this gist if some one needs the same functionality
SharedGraphViewModel.kt
This solved my issue https://stackoverflow.com/a/61316807/7046279
The problem is at org.koin.androidx.viewmodel.ViewModelResolver.kt:
private fun <T : ViewModel> Scope.pickFactory(
viewModelParameters: ViewModelParameter<T>,
): ViewModelProvider.Factory {
return when {
viewModelParameters.registryOwner != null && viewModelParameters.initialState != null -> StateViewModelFactory(this, viewModelParameters)
else -> DefaultViewModelFactory(this, viewModelParameters)
}
}
where the cause is viewModelParameters.initialState != null.
E.g. the wrong factory will be chosen if the state: BundleDefinition passed is null (DefaultViewModelFactory instead of StateViewModelFactory).
That's why passing an empty state as mentioned by @arctouch-andrecardoso (val viewModel: MyViewModel by viewModel(emptyState())) fixes the issue.
@arnaudgiuliani is it an expected behavior(therefore a bug in the documentation) or a bug?
I'm on 2.2.2 (with proper androidx both fragment and viewmodel extra dependencies), SavedStateHandle is the first parameter and I don't used SharedGraphViewModel - however I still get:
Caused by: org.koin.core.error.NoBeanDefFoundException: No definition found for class:'androidx.lifecycle.SavedStateHandle'. Check your definitions!
Also I found another weird behaviour. The order of parameters may cause this bug. When the "state" 1 or 2 in order, all working properly, but when state is as 4 by order getting this error.
I've also encountered this issue. Was working okay on 2.2.1 (which documentation lists it as the current stable which is a bit confusing) but after updating to 2.2.2 the app was crashing with org.koin.core.error.NoBeanDefFoundException. After some research I've landed on https://github.com/InsertKoinIO/koin/blob/master/CHANGELOG.md which says that DefaultViewModelFactory is used by default and StateViewModelFactory if a state parameter is passed so the following works for me:
val viewModel by viewModel<MyViewModel>(state = { Bundle.EMPTY })
@TepesLucian Thanks. Also you can use emptyState() instead of { Bundle.EMPTY }
Most helpful comment
I've also encountered this issue. Was working okay on
2.2.1(which documentation lists it as the currentstablewhich is a bit confusing) but after updating to2.2.2the app was crashing withorg.koin.core.error.NoBeanDefFoundException. After some research I've landed on https://github.com/InsertKoinIO/koin/blob/master/CHANGELOG.md which says thatDefaultViewModelFactoryis used by default andStateViewModelFactoryif astateparameter is passed so the following works for me: