When using the Accompanist AnimatedNavHost and navigation animations, if I go to a screen and then back (using system back button) quickly a few times in a row, the app crashes. I suspect this is a bug in Accompanist (I've submitted an issue on the Github repo), but I figured it was worth posting here as well, in case anybody else has seen this and/or has a workaround.
The app crashes with the following stacktrace:
java.util.NoSuchElementException: List contains no element matching the predicate.
at com.google.accompanist.navigation.animation.AnimatedNavHostKt$AnimatedNavHost$finalEnter$1$1.invoke(AnimatedNavHost.kt:341)
at com.google.accompanist.navigation.animation.AnimatedNavHostKt$AnimatedNavHost$finalEnter$1$1.invoke(AnimatedNavHost.kt:173)
at com.google.accompanist.navigation.animation.AnimatedNavHostKt$AnimatedNavHost$7$1.invoke(AnimatedNavHost.kt:244)
at com.google.accompanist.navigation.animation.AnimatedNavHostKt$AnimatedNavHost$7$1.invoke(AnimatedNavHost.kt:244)
at androidx.compose.animation.AnimatedContentKt.AnimatedContent(AnimatedContent.kt:664)
at com.google.accompanist.navigation.animation.AnimatedNavHostKt.AnimatedNavHost(AnimatedNavHost.kt:242)
at com.google.accompanist.navigation.animation.AnimatedNavHostKt$AnimatedNavHost$10.invoke(Unknown Source:23)
at com.google.accompanist.navigation.animation.AnimatedNavHostKt$AnimatedNavHost$10.invoke(Unknown Source:10)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:140)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2158)
at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2404)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:2585)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:2571)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(SnapshotState.kt:571)
at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:2571)
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:965)
at android.view.Choreographer.doCallbacks(Choreographer.java:791)
at android.view.Choreographer.doFrame(Choreographer.java:722)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:952)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
My navigation code is as follows:
AnimatedNavHost(navController = navController, startDestination = startDestinationString) {
composable(
route = "home",
) {
HomeScreen(
homeViewModel = homeViewModel,
navigateToBookDetail = { book ->
val arguments =
Bundle().apply {
putParcelable("book", book)
}
navController.navigate(route = "book_detail", args = arguments)
}
)
}
composable(
route = "book_detail",
enterTransition = { _, _ ->
slideInHorizontally(initialOffsetX = { 1500 }, animationSpec = tween(250))
},
popExitTransition = { _, _ ->
slideOutHorizontally(targetOffsetX = { 1500 }, animationSpec = tween(250))
}
) { backstackEntry ->
val book = backstackEntry.arguments?.getParcelable<Book>("book")
if (book != null) {
BookDetailScreen(viewModel = bookDetailViewModel, book = book)
}
}
}
To Reproduce
Navigate quickly between two screens, using the system back button to return to the first screen before the animation completes. In my case I'm triggering the animation and using the system back button before the animation completes. This usually takes a couple of tries before it crashes. Sometimes as little as two, sometimes five or ten.
Version 0.21.0-beta of Accompanist Animated Navigation