InsertKoinIO / koin

Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform
https://insert-koin.io
Apache License 2.0
9.03k stars 716 forks source link

java.lang.IllegalStateException: Compose Runtime internal error after updating to Koin 3.2.0 #1358

Closed racka98 closed 2 years ago

racka98 commented 2 years ago

Description After updating to Koin 3.2.0 from 3.1.6 my Compose app crashes with

java.lang.IllegalStateException: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Start/end imbalance).

Tried with 3.1.5 and 3.1.6 both work fine. Updating to 3.2.0 causes this crash. I believe this is a bug in Koin.

Also came across a similar issue on Google's issue tracker: https://issuetracker.google.com/issues/233126425 The author also appears to be using Koin.

Expected behavior App should not crash

Version koin-core version 3.2.0 koin-android version 3.2.0 koin-androidx-compose version 3.2.0

TheNephilim88 commented 2 years ago

+1 same here, needed to downgrade to 3.1.6 to get it working again.

Secack commented 2 years ago

any solutions?

arnaudgiuliani commented 2 years ago

any more stack trace or way to reproduce?

danielRi commented 2 years ago

politely bumping this issue.

nachtien commented 2 years ago

Stacktrace:

Java.lang.IllegalStateException: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Start/end imbalance). Please report to Google or use https://goo.gle/compose-feedback
at androidx.compose.runtime.ComposerKt.composeRuntimeError(Composer.kt:3466)
at androidx.compose.runtime.ComposerImpl.finalizeCompose(Composer.kt:3550)
at androidx.compose.runtime.ComposerImpl.endRoot(Composer.kt:1237)
at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:2588)
at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:2547)
at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:620)
at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:786)
at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:105)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:456)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:425)
at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34)
at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109)
at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41)
at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:997)
at android.view.Choreographer.doCallbacks(Choreographer.java:797)
at android.view.Choreographer.doFrame(Choreographer.java:728)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:984)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:8167)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.runtime.PausableMonotonicFrameClock@de5e03, StandaloneCoroutine{Cancelling}@8a52180, AndroidUiDispatcher@78473b9]
danielRi commented 2 years ago

I also got the crash but noticed if I move the line out of the setContent method the error seems to have vanished:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Moved the following line to here...
        val homePageViewModel: HomePageViewModel by viewModel()
        setContent {
            // ...Because here it caused the crash (commented out)
            // val homePageViewModel: HomePageViewModel by viewModel()
            val navController = rememberNavController()
            MaterialTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                ) {
                    NavHost(navController = navController, startDestination = "home") {
                        composable("home") { HomePage(navController, homePageViewModel) }
                        composable("search") { SearchPage() }
                        /*...*/
                    }
                }
            }
        }
    }
}

Not sure why the error occurs if I inject the viewModel within the setContent function

racka98 commented 2 years ago

I also got the crash but noticed if I move the line out of the setContent method the error seems to have vanished:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Moved the following line to here...
        val homePageViewModel: HomePageViewModel by viewModel()
        setContent {
            // ...Because here it caused the crash (commented out)
            // val homePageViewModel: HomePageViewModel by viewModel()
            val navController = rememberNavController()
            MaterialTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                ) {
                    NavHost(navController = navController, startDestination = "home") {
                        composable("home") { HomePage(navController, homePageViewModel) }
                        composable("search") { SearchPage() }
                        /*...*/
                    }
                }
            }
        }
    }
}

Not sure why the error occurs if I inject the viewModel within the setContent function

It vanishes because you are no longer using the compose specific methods for ViewModel. The issue is specific to using the compose viewModel() method inside compose. Moving everything out of compose kind of defeats the purpose

danielRi commented 2 years ago

@racka98 I think you should update your question or show your code to make it more clear for the developers.

arnaudgiuliani commented 2 years ago

an update is needed regarding ViewModel API & Compose 👍

Morons commented 2 years ago

I got the same

Version

koin_version = '3.2.0'

App Log

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: snipped ..., PID: 4643
    java.lang.IllegalStateException: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Start/end imbalance). Please report to Google or use https://goo.gle/compose-feedback
        at androidx.compose.runtime.ComposerKt.composeRuntimeError(Composer.kt:4244)
        at androidx.compose.runtime.ComposerImpl.finalizeCompose(Composer.kt:4390)
        at androidx.compose.runtime.ComposerImpl.endRoot(Composer.kt:1390)
        at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3208)
        at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:3148)
        at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:739)
        at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:876)
        at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:107)
        at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:485)
        at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:454)
        at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34)
        at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109)
        at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41)
        at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1229)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239)
        at android.view.Choreographer.doCallbacks(Choreographer.java:899)
        at android.view.Choreographer.doFrame(Choreographer.java:827)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214)
        at android.os.Handler.handleCallback(Handler.java:942)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7898)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
        Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.runtime.PausableMonotonicFrameClock@2e7902e, androidx.compose.ui.platform.MotionDurationScaleImpl@c1a97cf, StandaloneCoroutine{Cancelling}@aade55c, AndroidUiDispatcher@914e065]

Snipped ... Koin Log

D/[Koin]: +- '{snipped ...}.features.calculators.standard.presentation.CalculatorViewModel'
D/[Koin]: | create instance for [Factory:'{snipped ...}.features.calculators.standard.presentation.CalculatorViewModel']
D/[Koin]: +- '{snipped ...}.features.settings.domain.usecases.GetSettings'
D/[Koin]: | create instance for [Singleton:'{snipped ...}.features.settings.domain.usecases.GetSettings']
D/[Koin]: +- '{snipped ...}.core.repository.SettingsRepository'
D/[Koin]: | create instance for [Singleton:'{snipped ...}.core.repository.SettingsRepositoryImpl',binds:{ snipped ... }.core
.repository.SettingsRepository]
D/[Koin]: +- 'androidx.datastore.core.DataStore'
D/[Koin]: | create instance for [Singleton:'androidx.datastore.core.DataStore']
D/[Koin]: +- 'android.content.Context'
D/[Koin]: | create instance for [Singleton:'android.app.Application',binds:android.content.Context,android.app.Application]
D/[Koin]: |- 'android.content.Context' in 0.2217 ms
D/[Koin]: |- 'androidx.datastore.core.DataStore' in 13.4381 ms
D/[Koin]: |- '{snipped ...}.core.repository.SettingsRepository' in 15.7899 ms
D/[Koin]: |- '{snipped ...}.features.settings.domain.usecases.GetSettings' in 16.9416 ms
D/[Koin]: |- '{snipped ...}.features.calculators.standard.presentation.CalculatorViewModel' in 47.5962 ms
fardavide commented 2 years ago

Edit: That was my mistake, the assignment should be without delegation: = instead of by. Leaving here as a reference

I got a similar error, in a super basic composable, it crashes/got fixed by adding/removing the line #5

#1 import org.koin.androidx.compose.viewModel
#2
#3 @Composable
#4 fun HomeScreen(modifier: Modifier = Modifier) {
#5    val viewModel: HomeViewModel by viewModel()
#6    HomeScreen(state = HomeState.Idle, modifier = modifier)
#7 }

IntelliJ CE 2022.2 RC Gradle: 7.4.2 Multimodule Multiplatform project ( Compose modules are plain Jvm + Android, not KMP ) Kotin: 1.7.10 Compose: 1.3.0-alpha01 Compose compiler: 1.3.0-beta01 (edit: just tried with rc01 as well, same) Koin: 3.2.0

java.lang.IllegalStateException: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Start/end imbalance). Please report to Google or use https://goo.gle/compose-feedback
        at androidx.compose.runtime.ComposerKt.composeRuntimeError(Composer.kt:4244)
        at androidx.compose.runtime.ComposerImpl.finalizeCompose(Composer.kt:4390)
        at androidx.compose.runtime.ComposerImpl.endRoot(Composer.kt:1390)
        at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3208)
        at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3119)
        at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:578)
        at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:811)
        at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:513)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:140)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:131)
        at androidx.compose.ui.platform.AndroidComposeView.setOnViewTreeOwnersAvailable(AndroidComposeView.android.kt:1052)
        at androidx.compose.ui.platform.WrappedComposition.setContent(Wrapper.android.kt:131)
        at androidx.compose.ui.platform.WrappedComposition.onStateChanged(Wrapper.android.kt:182)
        at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:360)
        at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.java:202)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:138)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:131)
        at androidx.compose.ui.platform.AndroidComposeView.onAttachedToWindow(AndroidComposeView.android.kt:1139)
        at android.view.View.dispatchAttachedToWindow(View.java:20479)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3489)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3496)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3496)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3496)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3496)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2417)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1952)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8171)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
        at android.view.Choreographer.doCallbacks(Choreographer.java:796)
        at android.view.Choreographer.doFrame(Choreographer.java:731)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
        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)
zeromod commented 2 years ago

This might be a duplicate of #1347 and a possible workaround is to replace lazy viewModel with getViewModel

arnaudgiuliani commented 2 years ago

Yep, seems something to do with Lazy. I'm currently investigating on it 👍

arnaudgiuliani commented 2 years ago

The root cause is that we are now using closely the ViewModel API from Google and it doesn't support any kind of Lazy or ViewModelLazy retuned type in Compose 1.1+

Best is to use the eager API: koinViewModel() or even get()

I will deprecate with error lazy APIs of koin-androidx-compose in 3.2.1