Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No definition found for class:'androidx.lifecycle.SavedStateHandle' #963

Closed
OleksandrGrument opened this issue Nov 26, 2020 · 35 comments
Closed
Labels
android documentation status:checking currently in analysis - discussion or need more detailed specs type:issue
Milestone

Comments

@OleksandrGrument
Copy link

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):
[e.g]: koin-core version 2.2.1

Any help apreciated

@OleksandrGrument
Copy link
Author

OleksandrGrument commented Nov 30, 2020

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.

@dendrocyte
Copy link

same here with @OleksandrGrument

@arnaudgiuliani arnaudgiuliani added type:issue status:checking currently in analysis - discussion or need more detailed specs android labels Dec 17, 2020
@arnaudgiuliani
Copy link
Member

can be a problem with new default ViewModel factory 🤔

@arnaudgiuliani
Copy link
Member

it's curious that it's looking for default state bundle

.NoBeanDefFoundException: No definition found for class:'androidx.lifecycle.SavedStateHandle'

@arctouch-andrecardoso
Copy link

arctouch-andrecardoso commented Dec 29, 2020

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 😱

@jsaumellbasetis
Copy link

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.

@jsaumellbasetis
Copy link

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.

@arctouch-andrecardoso
Copy link

@jsaumellbasetis I'm using import org.koin.androidx.viewmodel.scope.emptyState as it is done in the example here.

@jsaumellbasetis
Copy link

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.

@antonsarmatin
Copy link

Similar problem if the savedStateHandle parameter is not the first.
Weird.

@thats-bot
Copy link

    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?

exception.TXT

@thats-bot
Copy link

It seems I figurre it out. Please have a look at this gist if some one needs the same functionality
SharedGraphViewModel.kt

@josephsarz
Copy link

This solved my issue https://stackoverflow.com/a/61316807/7046279

@adenisyuk
Copy link

adenisyuk commented Jan 14, 2021

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?

@tajchert
Copy link
Contributor

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!

@OleksandrGrument
Copy link
Author

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.

@TepesLucian
Copy link

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

@ALXKAY
Copy link

ALXKAY commented Jan 29, 2021

@TepesLucian Thanks. Also you can use emptyState() instead of { Bundle.EMPTY }

@c-b-h
Copy link

c-b-h commented Feb 2, 2021

This is the signature of the ViewModel I had issues with:

class QuizViewModel(
    savedStateHandle: SavedStateHandle,
    quizId: String,
    cardId: String,
    context: Context,
    service: Service,
) : ViewModel()

and I defined the viewModel as such:

module {
    viewModel { (quizId: String, cardId: String) ->
        QuizViewModel(get(), quizId, cardId, get(), get())
    }

and consumed it like so:

val viewModel by viewModel<QuizViewModel>(state = emptyState()) {
        parametersOf("some id", "another id")
}

…without using the emptyState() solution I would get the same crash and I'm on 2.2.2 too. As can be noted I am both passing savedStateHandle AND other non-koin-obtained parameters.

@gmk57
Copy link

gmk57 commented Feb 12, 2021

@TepesLucian @ALXKAY @c-b-h Doesn't passing emptyState() or { Bundle.EMPTY } defeat the whole purpose of ViewModel Saved State mechanism?

I also suppose the bug in 2.2.2 deserves a thread of its own.

@TepesLucian
Copy link

@gmk57 not really since you can use that bundle to apply initial params to SavedStateHandle (e.g. pass a fragment argument in there as an initial state). I do agree that the documentation is missing since i needed to dig on my own in their changelog to figure out the emptyState() / { Bundle.EMPTY } params that i needed to pass.

@arctouch-andrecardoso
Copy link

The documentation is also not clear that SavedStateHandle must be the first parameter

@arnaudgiuliani
Copy link
Member

arnaudgiuliani commented Mar 3, 2021

Koin 3.0.1 makes parameters available in the Koin graph. This means that we can resolve anything with get() even injection parameters.

@arnaudgiuliani arnaudgiuliani added this to the 3.0.1 milestone Mar 3, 2021
@arnaudgiuliani
Copy link
Member

StateViewModel API has been restored in 3.0.1, with consistent factory resolution.

@sagarpatel288
Copy link

@arnaudgiuliani How do we do that in 2.2.3 with by inject()?

@arnaudgiuliani
Copy link
Member

@sagarpatel288 no, just use by viewModel( state = <Your bundle>)

@sagarpatel288
Copy link

@arnaudgiuliani Thanks for the quick reply. It says unresolved reference for by viewModel.

Here are the details:

Classpath

def koin_version = "2.2.3"
        classpath "io.insert-koin:koin-gradle-plugin:$koin_version"

Plugin

apply plugin: 'koin'

Dependencies


    //Koin
    def koin_version = "2.2.3"

    // Koin Core
    // Koin for Kotlin
   implementation "io.insert-koin:koin-core:$koin_version"
    // Koin extended & experimental features
    implementation "io.insert-koin:koin-core-ext:$koin_version"

    // Koin AndroidX Scope features
    implementation "io.insert-koin:koin-androidx-scope:$koin_version"
    // Koin AndroidX ViewModel features
    implementation "io.insert-koin:koin-androidx-viewmodel:$koin_version"
    implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.0"
    // Koin AndroidX Fragment features
    implementation "io.insert-koin:koin-androidx-fragment:$koin_version"
    // Koin AndroidX WorkManager
    implementation "io.insert-koin:koin-androidx-workmanager:$koin_version"
    // Koin AndroidX Experimental features
    implementation "io.insert-koin:koin-androidx-ext:$koin_version"
 
    // Koin for Ktor Kotlin
    implementation "io.insert-koin:koin-ktor:$koin_version"

Module

@OptIn(KoinApiExtension::class)
val viewModelModules = module {
    viewModel {
        MeetingViewModel(get())
    }

    factory {
        emptyState()
    }
}

ViewModel

@KoinApiExtension
class MeetingViewModel(val savedStateHandle: SavedStateHandle) : ViewModel() {

Service class

@KoinApiExtension
class ChimeService : LifecycleService()

Usage in the service class

 val meetingViewModel: MeetingViewModel by viewModel( state = emptyState())

Confirmed the Import statement in the service class
import org.koin.androidx.viewmodel.ext.android.viewModel

@sagarpatel288
Copy link

The current solution is inspired from here:

https://insert-koin.io/docs/reference/koin-core/injection-parameters/

Module

@OptIn(KoinApiExtension::class)
val viewModelModules = module {
    viewModel {
            (savedStateHandle: SavedStateHandle) -> MeetingViewModel(savedStateHandle)
    }
}

Usage in the service class

val meetingViewModel: MeetingViewModel by inject { parametersOf(SavedStateHandle())}

I hope I am using it properly. Looking for a better way though.

@arnaudgiuliani
Copy link
Member

The usage is not good. It should be val meetingViewModel: MeetingViewModel by viewModel(state = <YourBundle>)

@sagarpatel288
Copy link

Yeah... How can I solve "unresolved reference" while trying to use by viewModel there? What am I missing here?

@arnaudgiuliani
Copy link
Member

if you gradle config is good, be sure to make the import for extension function.

@sagarpatel288
Copy link

Below import is there but it is not being used even when I use by viewModel

import org.koin.androidx.viewmodel.ext.android.viewModel

@SameerShelarr
Copy link

I m facing this issue while injecting a ViewModel having SavedStateHandle as one of the constructor parameter.

Setup:

class SampleApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        startKoin {
            printLogger()
            androidContext(this@SampleApplication)
            modules(appModule)
        }
    }
}

Module:

val appModule = module {

    factoryOf(::SampleUseCase)

    viewModelOf(::SampleViewModel)
}

Composable:

@Composable
fun SampleComposable(
    navController: NavController,
    viewModel: SampleViewModel = get(),
)

ViewModel:

class SampleViewModel constructor(
    savedStateHandle: SavedStateHandle,
    private val sampleUseCase: SampleUseCase,
) : ViewModel()

I m using koin_version = '3.2.0', kotlin_version='1.7.0', compose_version = '1.2.0'

Dependencies in build.gradle:

// Koin DI
implementation "io.insert-koin:koin-core:$koin_version"
implementation "io.insert-koin:koin-test:$koin_version"
implementation "io.insert-koin:koin-android:$koin_version"
implementation "io.insert-koin:koin-androidx-compose:$koin_version"

@hakobvardanyan
Copy link

@SameerShelarr I have downgraded the koin_version to 3.1.5 and it worked for me. I assume this is a bug in the 3.2.0 version.

@kassim
Copy link

kassim commented May 3, 2024

Hi. I'm seeing this same issue reported in io.insert-koin:koin-android:3.4.3 – its not a consistent issue that we can recreate but it's being reported via Google Play console.
Our usage is calling koinViewModel(), called from within a composable, within a fragment.

Caused by rw.b: No definition found for class:'androidx.lifecycle.SavedStateHandle' q:''. Check your definitions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
android documentation status:checking currently in analysis - discussion or need more detailed specs type:issue
Projects
None yet
Development

No branches or pull requests