vide
11/22/2023, 7:51 PMLaunchedEffect
would always run on the main thread? I have a LauncedEffect
calling navigate like this:
LaunchedEffect(key, ...) { navController.navigate(...) { popUpTo(...) } }
And very rarely when running instrumented tests, I get this exception. Am I missing something? Full stack trace in thread.
java.lang.IllegalStateException: Method setCurrentState must be called on the main thread
vide
11/22/2023, 7:56 PMjava.lang.IllegalStateException: Method setCurrentState must be called on the main thread
at androidx.lifecycle.LifecycleRegistry.enforceMainThreadIfNeeded(LifecycleRegistry.kt:296)
at androidx.lifecycle.LifecycleRegistry.setCurrentState(LifecycleRegistry.kt:105)
at androidx.navigation.NavBackStackEntry.updateState(NavBackStackEntry.kt:188)
at androidx.navigation.NavBackStackEntry.setMaxLifecycle(NavBackStackEntry.kt:159)
at androidx.navigation.NavController.popEntryFromBackStack(NavController.kt:761)
at androidx.navigation.NavController.access$popEntryFromBackStack(NavController.kt:68)
at androidx.navigation.NavController$executePopOperations$1.invoke(NavController.kt:643)
at androidx.navigation.NavController$executePopOperations$1.invoke(NavController.kt:640)
at androidx.navigation.NavController$NavControllerNavigatorState.pop(NavController.kt:330)
at androidx.navigation.NavigatorState.popWithTransition(NavigatorState.kt:149)
at androidx.navigation.NavController$NavControllerNavigatorState.popWithTransition(NavController.kt:343)
at androidx.navigation.compose.ComposeNavigator.popBackStack(ComposeNavigator.kt:67)
at androidx.navigation.NavController.popBackStackInternal(NavController.kt:280)
at androidx.navigation.NavController.executePopOperations(NavController.kt:640)
at androidx.navigation.NavController.popBackStackInternal(NavController.kt:627)
at androidx.navigation.NavController.navigate(NavController.kt:1837)
at androidx.navigation.NavController.navigate(NavController.kt:1812)
at androidx.navigation.NavController.navigate(NavController.kt:2220)
at androidx.navigation.NavController.navigate$default(NavController.kt:2215)
at androidx.navigation.NavController.navigate(NavController.kt:2200)
at <mypackage>(:19) <- helper functions
at <mypackage>(:17) <- helper functions
at <mypackage>.invokeSuspend(:266) <- in a LaunchedEffect
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at androidx.compose.ui.test.ApplyingContinuationInterceptor$SendApplyContinuation.resumeWith(ApplyingContinuationInterceptor.kt:65)
at androidx.compose.ui.test.FrameDeferringContinuationInterceptor$TrampolinedTask.resume(FrameDeferringContinuationInterceptor.kt:137)
at androidx.compose.ui.test.FrameDeferringContinuationInterceptor.runWithoutResumingCoroutines(FrameDeferringContinuationInterceptor.kt:75)
at androidx.compose.ui.test.TestMonotonicFrameClock.performFrame(TestMonotonicFrameClock.jvm.kt:132)
at androidx.compose.ui.test.TestMonotonicFrameClock.access$performFrame(TestMonotonicFrameClock.jvm.kt:53)
at androidx.compose.ui.test.TestMonotonicFrameClock$withFrameNanos$2$1$2.invokeSuspend(TestMonotonicFrameClock.jvm.kt:110)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:367)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source:1)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1)
at androidx.compose.ui.test.TestMonotonicFrameClock.withFrameNanos(TestMonotonicFrameClock.jvm.kt:108)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2.invokeSuspend(Recomposer.kt:548)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at androidx.compose.ui.test.ApplyingContinuationInterceptor$SendApplyContinuation.resumeWith(ApplyingContinuationInterceptor.kt:65)
at androidx.compose.ui.test.FrameDeferringContinuationInterceptor$FrameDeferredContinuation.resumeWith(FrameDeferringContinuationInterceptor.kt:194)
at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:179)
at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:168)
at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:474)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:508)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:497)
at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:368)
at androidx.compose.runtime.Recomposer$recompositionRunner$2$unregisterApplyObserver$1.invoke(Recomposer.kt:979)
at androidx.compose.runtime.Recomposer$recompositionRunner$2$unregisterApplyObserver$1.invoke(Recomposer.kt:973)
at androidx.compose.runtime.snapshots.SnapshotKt.advanceGlobalSnapshot(Snapshot.kt:1815)
at androidx.compose.runtime.snapshots.SnapshotKt.advanceGlobalSnapshot(Snapshot.kt:1830)
at androidx.compose.runtime.snapshots.SnapshotKt.access$advanceGlobalSnapshot(Snapshot.kt:1)
at androidx.compose.runtime.snapshots.Snapshot$Companion.sendApplyNotifications(Snapshot.kt:583)
at androidx.compose.ui.test.ApplyingContinuationInterceptor$SendApplyContinuation.resumeWith(ApplyingContinuationInterceptor.kt:66)
at androidx.compose.ui.test.FrameDeferringContinuationInterceptor$FrameDeferredContinuation.resumeWith(FrameDeferringContinuationInterceptor.kt:194)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:283)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith$default(DispatchedContinuation.kt:278)
at kotlinx.coroutines.internal.ScopeCoroutine.afterCompletion(Scopes.kt:27)
at kotlinx.coroutines.JobSupport.continueCompleting(JobSupport.kt:940)
at kotlinx.coroutines.JobSupport.access$continueCompleting(JobSupport.kt:25)
at kotlinx.coroutines.JobSupport$ChildCompletion.invoke(JobSupport.kt:1159)
at kotlinx.coroutines.JobSupport.notifyCompletion(JobSupport.kt:1497)
at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:325)
at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:242)
at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:910)
at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:867)
at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:832)
at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:100)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at androidx.compose.ui.test.ApplyingContinuationInterceptor$SendApplyContinuation.resumeWith(ApplyingContinuationInterceptor.kt:65)
at androidx.compose.ui.test.FrameDeferringContinuationInterceptor$FrameDeferredContinuation.resumeWith(FrameDeferringContinuationInterceptor.kt:194)
at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:179)
at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:168)
at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:474)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:508)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:497)
at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:368)
at kotlinx.coroutines.ResumeOnCompletion.invoke(JobSupport.kt:1391)
at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:320)
at kotlinx.coroutines.JobSupport.tryFinalizeSimpleState(JobSupport.kt:297)
at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:860)
at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:832)
at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:100)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
Zach Klippenstein (he/him) [MOD]
11/22/2023, 8:48 PMvide
11/22/2023, 8:57 PMZach Klippenstein (he/him) [MOD]
11/22/2023, 8:59 PMZach Klippenstein (he/him) [MOD]
11/22/2023, 8:59 PMat <mypackage>(:19) <- helper functions
at <mypackage>(:17) <- helper functions
at <mypackage>.invokeSuspend(:266) <- in a LaunchedEffect
is switching threads?vide
11/22/2023, 9:12 PMLaunchedEffect
doesn't do any context switchesshikasd
11/22/2023, 9:12 PMsetContent
from the test thread, it is possible that LaunchedEffect
also going to execute in the same threadvide
11/22/2023, 9:13 PMmyanmarking
11/22/2023, 9:15 PMvide
11/22/2023, 9:17 PMZach Klippenstein (he/him) [MOD]
11/22/2023, 9:18 PMif you callIt shouldn’t though, and if it did then it would fail much more regularly since that’s the main recommended way to use it.from the test thread, it is possible thatsetContent
also going to execute in the same threadLaunchedEffect
myanmarking
11/22/2023, 9:18 PMvide
11/22/2023, 9:18 PMZach Klippenstein (he/him) [MOD]
11/22/2023, 9:18 PMshikasd
11/22/2023, 9:19 PMApplyingContinuationInterceptor$SendApplyContinuation
and TestMonotonicClock
is in the trace that is not supposed to be mainZach Klippenstein (he/him) [MOD]
11/22/2023, 9:20 PMvide
11/22/2023, 9:21 PMvide
11/22/2023, 10:30 PMZach Klippenstein (he/him) [MOD]
11/22/2023, 10:31 PMvide
11/22/2023, 10:32 PMvide
11/23/2023, 9:26 AM11-23 11:18:55.592 2224 2327 V CX_LoadingPage: LoadingPage LaunchedEffect running on thread Thread[DefaultDispatcher-worker-20,5,main]
Zach Klippenstein (he/him) [MOD]
11/23/2023, 9:18 PMvide
02/20/2025, 1:53 PMLaunchedEffect(...) {
withContext(<http://Dispatchers.IO|Dispatchers.IO>) { Log.d("DEBUG", "Hello, world!") }
Log.d("DEBUG", "Hello, {Thread.currentThread()}!") // on a worker thread
}
vide
02/20/2025, 1:54 PMZach Klippenstein (he/him) [MOD]
02/20/2025, 2:01 PMvide
02/20/2025, 2:41 PMshikasd
02/22/2025, 4:36 AM