Восстановление навигационного стека не удалось: назначение 30355061 не может быть найдено из текущего назначения mj0(0x0) startDestination={oj0(0x2e873c) route=x.x.x.x.composeNavigation.MenuScreen}
У меня есть проект на Jetpack Compose, где я использую типобезопасную навигацию, и я вижу множество сбоев в Firebase.
import kotlinx.serialization.Serializable
@Serializable
object QrCodeScreenScanner
@Serializable
data class OtpScreen(val otpCode: String)
@Serializable
data class SignatureDataOverviewScreen(val transactionId: String, val payload: String)
@Serializable
data class SignatureHashOverlayScreen(val otpCode: String)
@Serializable
object MenuScreen
@Serializable
object AskForNotificationPermissionScreen
@Serializable
data class UpdateNeededScreen(val cancellable: Boolean)
class MenuActivity : ComponentActivity() {
companion object {
const val ENROLMENT_COMPLETED = "ENROLMENT_COMPLETED"
}
private val navigator: Navigator by inject { parametersOf(this@MenuActivity) }
private val menuViewModel: MenuViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
var permissionDialogScreenAlreadyShowed = remember { false }
Theme {
NavHost(navController = navController, startDestination = MenuScreen) {
composable<MenuScreen> {
val uiState by menuViewModel.uiState.collectAsStateWithLifecycle()
MenuScreen(
uiState = uiState,
navigator = navigator,
navigateToAskForNotificationPermission = {
navController.navigate(AskForNotificationPermissionScreen)
},
enrolmentStates = menuViewModel.subscribeToEnrolmentState(),
permissionDialogScreenAlreadyShowed = permissionDialogScreenAlreadyShowed,
uiEvents = menuViewModel.uiEvent,
isOnline = menuViewModel.isOnline,
menuItemIntentAction = menuViewModel::setMenuViewModelIntent,
appUpdateCheckNeeded = menuViewModel.appUpdateCheckNeeded,
navigateToShowUpdateScreen = { cancellable ->
navController.navigate(UpdateNeededScreen(cancellable))
},
)
}
composable<AskForNotificationPermissionScreen> {
RequestNotificationPermissionScreen(
navigateToMenuScreen = {
permissionDialogScreenAlreadyShowed = true
navController.navigate(MenuScreen)
}
)
}
composable<UpdateNeededScreen> {
ShowAppUpdateScreen(
cancellable = true,
navigateToMenuScreen = {
navController.navigate(MenuScreen)
}
)
}
}
}
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
intent.extras?.let { extras ->
val confirmationToken =
extras.getString(this.getString(R.string.ENROLMENT_CHALLENGE), "")
val deviceName =
extras.getString(this.getString(R.string.ENROLMENT_DEVICENAME), "")
Timber.d("Confirmation token: %s", confirmationToken ?: "(пусто)")
Timber.d("DeviceName: %s", deviceName ?: "(пусто)")
if (!confirmationToken.isNullOrBlank() && !deviceName.isNullOrBlank()) {
menuViewModel.setMenuViewModelIntent(
MenuViewModelIntent.ProcessEnrolment(
confirmationToken = confirmationToken,
deviceName = deviceName
)
)
return
}
val isEnrolmentCompleted = extras.getBoolean(ENROLMENT_COMPLETED, false)
if (isEnrolmentCompleted) {
navigator.navigateTo(NavigatorRoute.ENROLMENT_COMPLETED)
}
}
}
}
У меня архитектура с несколькими модулями, где у каждого модуля есть своя навигационная графика.
Кто-то сталкивался с этой проблемой ранее? Я использую новый способ безопасности типов для навигации. Локально все работает как ожидалось, но я вижу много ошибок в Firebase Crashlytics. Почему?
Ответ
Ваша проблема связана с тем, что используется типобезопасная навигация в Jetpack Compose, и возникают ошибки с восстановлением стека навигации. Ошибка, которую вы видите, указывает, что приложение пытается вернуться к экрану, который не был найден в текущем навигационном графе.
Возможные причины проблемы и их решения:
-
Неправильная конфигурация навигационного графа: Ваша архитектура с несколькими модулями может приводить к тому, что некоторые экраны не представлены в текущем графе навигации. Убедитесь, что при добавлении новых экранов вы обновляете все необходимые навигационные графы.
Решение: Проверьте, что все экраны из всех модулей корректно добавлены в соответствующий навигационный граф. Убедитесь, что идентификаторы экранов (например,
MenuScreen
,AskForNotificationPermissionScreen
и т.д.) не конфликтуют и правильно используются. -
Использование
navController.navigate()
: Пожалуйста, обратите внимание на то, как вы используете методnavigate()
. Если вы пытаетесь выполнить навигацию к экрану, который в данный момент не доступен (например, экран не был инициализирован или уже был удалён из стека), это может привести к подобным ошибкам.Решение: Убедитесь, что переходы между экранами всегда происходят в контексте доступного стека навигации. Например, перед навигацией проверяйте состояние текущего экрана и его доступность.
-
Обработка
onNewIntent
: Проверьте, как в вашем методеonNewIntent
обрабатываются новые интенты. Если новое намерение приводит к навигации, которая еще не завершилась или не корректна, вы можете столкнуться с проблемами.Решение: Рассмотрите возможность проверки состояния перед вызовом навигации из
onNewIntent
. Например, добавьте дополнительные проверки и условия для выполнения навигации только в том случае, если текущее состояние это позволяет. -
Файлы ресурсов и локализация: Убедитесь, что в ваших ресурсах (например, строках) нет дублирующихся или недоступных значений, которые могут вызывать сбои.
-
Логирование и отладка: Используйте инструменты логирования, такие как Timber, чтобы выводить состояния навигации на консоль. Это может дать вам представление о том, какие действия выполняются до возникновения ошибки.
Пример логирования:
Timber.d("Navigating to: ${destination.route}")
Заключение
Некоторые из этих проблем сложно выявить без подробного анализа вашего кода и архитектуры. Убедитесь, что каждая часть вашего приложения не зависит от другой в контексте навигации, и каждая навигация безопасна и контролируемая. Если проблема сохраняется, рассмотрите возможность предоставления более информации в вопросы поддержки для более детального анализа.