NavigationBarのNavigationBarItemを何度もタップすることにより、アプリが強制終了する場合の対処法
NavigationBar
のNavigationBarItem
を何度もタップし、最後に一番左のNavigationBarItem
を連打するとアプリがクラッシュする現象に遭遇した。
これがその時のエラーの抜粋。
java.util.NoSuchElementException: List contains no element matching the predicate. at androidx.navigation.compose.NavHostKt$NavHost$4.invoke(NavHost.kt:180) at androidx.navigation.compose.NavHostKt$NavHost$4.invoke(NavHost.kt:141) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116) at androidx.compose.runtime.internal.ComposableLambdaImpl$invoke$1.invoke(ComposableLambda.jvm.kt:127) at androidx.compose.runtime.internal.ComposableLambdaImpl$invoke$1.invoke(ComposableLambda.jvm.kt:127) at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:145) at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2375)
例外が発生している箇所は、NavHost
のlast()
メソッドの呼び出し部分だった。
// classes.jar/androidx/navigation/compose/NavHostKt.class if (backStackEntry != null) { // while in the scope of the composable, we provide the navBackStackEntry as the // ViewModelStoreOwner and LifecycleOwner Crossfade(backStackEntry.id, modifier) { val lastEntry = visibleEntries.last { entry -> it == entry.id }
大元を辿るとnavigate()
メソッドを呼び出している箇所によるものだった。
navController.navigate(newRoute) {
popUpTo(navController.graph.findStartDestination().id) {}
launchSingleTop = true
}
どうやら、特定の条件下において同じ遷移先に対して何度もnavigate()
メソッドを呼び出そうとするとクラッシュするようだ。
なので、これから遷移しようとしている先が現在のルートと被っていないかを確認する処理を挟んであげることで解決した。
fun navigateAndPopUp( destination: TnaNavigationDestination, route: String? = null, from: NavBackStackEntry? = try { navController.currentBackStackEntry } catch(err: Exception) { null } ) { if (from != null && from.lifecycleIsResumed()) { val newRoute = when (destination) { is TopLevelDestination -> { destination.destination } else -> { route ?: destination.route } } when(newRoute) { from.destination.route -> { /* 何もしない */ } else -> { navController.navigate(newRoute) { popUpTo(navController.graph.findStartDestination().id) {} launchSingleTop = true } } } } }
参考
android - Collection contains no element matching the predicate - Stack Overflow