Irbisa · Шпаргалка
Навигация в Android
Navigation Component, Safe Args, типизированные маршруты, deep links, back stack, predictive back
В приложении с одной Activity и
NavHostпользователь нажимает «Назад». Что происходит и с какого стека снимается экран?Чем Up отличается от Back?
Почему в аргумент навигации передают id, а не весь объект?
Как передать аргументы между destination: Safe Args или
@Serializable-маршруты?// Type-safe routes (Navigation 2.8+)@Serializable data object Home@Serializable data class Detail(val orderId: Long, val title: String? = null) NavHost(navController, startDestination = Home) { composable<Home> { HomeScreen(onOpen = { id -> navController.navigate(Detail(id)) }) }…Что делают
popUpTo,inclusiveиlaunchSingleTop, и как убрать экраны логина из стека после входа?@Serializable data object AuthGraph@Serializable data object Login@Serializable data object Otp@Serializable data object Home NavHost(navController, startDestination = AuthGraph) {…Что такое вложенный граф навигации и как привязать ViewModel к нему?
@Serializable data object Home@Serializable data object WizardGraph@Serializable data object Step1@Serializable data object Step2 data class Draft(val text: String = "")…Как вернуть результат с экрана на предыдущий?
// Picker: write into the caller's handle, then popcomposable<Picker> { AddressList(onPick = { address -> navController.previousBackStackEntry ?.savedStateHandle ?.set("picked_address_id", address.id) // an id, never the object…Найдите баг: после выбора города
CityPickerзакрывается, но экран поиска так и не показывает город.NavHost(navController, startDestination = Home) { composable<Home> { HomeScreen(onSearch = { navController.navigate(Search) }) } composable<Search> { entry -> val cityId by entry.savedStateHandle .getStateFlow<Long?>("city_id", null) .collectAsStateWithLifecycle() SearchScreen(cityId, onPickCity = { navController.navigate(CityPicker) }) } composable<CityPicker> { CityList(onPick = { city -> navController.popBackStack() navController.previousBackStackEntry ?.savedStateHandle?.set("city_id", city.id) }) }}Пользователи жалуются: «Назад» проходит по всем нажатым вкладкам, а каждая вкладка забывает скролл и глубину. Что не так с этим нижним меню?
val current by navController.currentBackStackEntryAsState() NavigationBar { tabs.forEach { tab -> NavigationBarItem( selected = current?.destination?.hasRoute(tab.route::class) == true, onClick = { navController.navigate(tab.route) }, icon = { Icon(tab.icon, contentDescription = null) }, label = { Text(tab.label) } ) }}Этот экран иногда кладёт Login в стек дважды. Почему, и где должна жить проверка логина?
@Composablefun ProfileScreen(loggedIn: Boolean, navController: NavController) { if (!loggedIn) { navController.navigate(Login) } ProfileContent()}Найдите баг: быстрый двойной тап по заказу открывает его детали дважды, и первое «Назад» снова показывает тот же заказ.
composable<Orders> { val vm: OrdersViewModel = hiltViewModel() val orders by vm.orders.collectAsStateWithLifecycle() LazyColumn { items(orders, key = { it.id }) { order -> OrderRow( order = order, onClick = { navController.navigate(OrderDetail(order.id)) } ) } }}Deep link из уведомления открывает детали заказа, а «Назад» ведёт на Home (или закрывает приложение) вместо списка заказов. Как исправить стек?
@Serializable data object Home@Serializable data object OrdersGraph@Serializable data object OrderList@Serializable data class OrderDetail(val id: Long) NavHost(navController, startDestination = Home) {…Чем deep link отличается от Android App Link и как App Link проходит верификацию?
<activity android:name=".MainActivity" android:exported="true"> <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="https"…NavBackStackEntryодновременно реализуетLifecycleOwner,ViewModelStoreOwnerиSavedStateRegistryOwner. Что это значит для состояния экрана?Одна Activity или несколько: что выбрать в 2026 году и когда вторая Activity оправдана?
Что такое predictive back и что нужно поменять в существующем приложении для его поддержки?
// wrong: the system cannot know in advance that Back is handled hereoverride fun onBackPressed() { if (hasUnsavedChanges) showDiscardDialog() else super.onBackPressed()} // right: state sets isEnabled before the gesture starts…Как тестировать навигацию в Compose-приложении?
// The screen: assert the callback, no NavController involved@Test fun tappingRowReportsOrderId() { var opened: Long? = null composeRule.setContent { OrderList(orders = sample, onOpenOrder = { opened = it }) } composeRule.onNodeWithText("Order #42").performClick() assertEquals(42L, opened)…Как в многомодульном приложении
:feature:checkoutоткрывает экран из:feature:profile, не завися от него?// :feature:checkout - knows nothing about :feature:profile@Serializable data object Checkout fun NavGraphBuilder.checkoutSection(onOpenProfile: (Long) -> Unit) { composable<Checkout> { CheckoutScreen(onOpenProfile = onOpenProfile) }}…На планшете список и детали видны рядом. Почему пушить детали отдельным destination неправильно и что использовать вместо этого?
// In the NavHost the whole screen is ONE destination: composable<Inbox> { MailScreen() }@Composablefun MailScreen() { val panes = rememberListDetailPaneScaffoldNavigator<Long>() // pane history + selection val scope = rememberCoroutineScope()…Что такое Navigation 3 и что меняется по сравнению с
NavController?@Serializable data object Home : NavKey@Serializable data object Login : NavKey@Serializable data class Article(val id: Long) : NavKey @Composablefun App(loggedIn: Boolean) {…