Быстрая навигация с помощью анимированной навигации аккомпаниатора в Jetpack Compose вызывает сбой приложения

При использовании AnimatedNavHost и анимации навигации, если я выйду на экран, а затем быстро вернусь (с помощью системной кнопки «Назад») несколько раз подряд, приложение выйдет из строя. Я подозреваю, что это ошибка в «Сопровождающем» (я представил проблему в репозитории Github), но я подумал, что ее стоит опубликовать и здесь, на случай, если кто-то еще видел это и / или нашел обходной путь.

Приложение вылетает со следующей трассировкой стека:

      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)

Мой код навигации выглядит следующим образом:

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

Воспроизводить

Быстро перемещайтесь между двумя экранами, используя системную кнопку «Назад», чтобы вернуться к первому экрану до завершения анимации. В моем случае я запускаю анимацию и использую системную кнопку «Назад» до завершения анимации. Обычно это требует пары попыток, прежде чем произойдет сбой. Иногда всего два, иногда пять или десять.

Версия 0.21.0-beta анимированной навигации для аккомпаниаторов

1 ответ

Решение

У меня была та же проблема, когда переключение между вкладками на быстрое запускало одно и то же исключение, но, к счастью, я нашел код от Филиппа Духова. У него была та же проблема, и решение состояло в том, чтобы запустить сопрограмму и отменить ее при навигации до завершения анимации.

Другие вопросы по тегам