Навигация и задний стек

NavController содержит «обратный стек», содержащий пункты назначения, которые посетил пользователь. Когда пользователь перемещается по экранам вашего приложения, NavController добавляет и удаляет пункты назначения в заднем стеке и из него.

Будучи стеком, задний стек представляет собой структуру данных «последним пришел — первым ушел». Таким образом, NavController помещает элементы в верхнюю часть стека и извлекает их из нее.

Основное поведение

Вот основные факты, которые следует учитывать в отношении поведения обратного стека:

  • Первый пункт назначения: когда пользователь открывает приложение, NavController помещает первый пункт назначения в начало заднего стека.
  • Занесение в стек: каждый вызов NavController.navigate() помещает заданный пункт назначения в вершину стека.
  • Выдвижение верхнего пункта назначения: нажатие « Вверх» или «Назад» вызывает методы NavController.navigateUp() и NavController.popBackStack() соответственно. Они извлекают верхний пункт назначения из стека. См. страницу «Принципы навигации» для получения дополнительной информации о разнице между «Вверх» и «Назад» .

Вернитесь назад

Метод NavController.popBackStack() пытается извлечь текущий пункт назначения из заднего стека и перейти к предыдущему пункту назначения. Это эффективно перемещает пользователя на один шаг назад в истории навигации. Он возвращает логическое значение, указывающее, успешно ли он вернулся в пункт назначения.

Вернитесь к определенному пункту назначения

Вы также можете использовать popBackStack() для перехода к определенному пункту назначения. Для этого используйте одну из его перегрузок. Некоторые из них позволяют передавать идентификатор, например целочисленный id или строковый route . Эти перегрузки доставляют пользователя к месту назначения, связанному с данным идентификатором. Что особенно важно, они извлекают все, что находится в стеке выше этого пункта назначения.

Эти перегрузки также принимают inclusive логическое значение. Он определяет, должен ли NavController также извлечь указанный пункт назначения из заднего стека после перехода к нему.

Рассмотрим этот краткий фрагмент в качестве примера:

navController.popBackStack(R.id.destinationId, true) 

Здесь NavController возвращается к месту назначения с целочисленным идентификатором destinationId . Поскольку значение inclusive аргумента равно true , NavController также извлекает указанный пункт назначения из заднего стека.

Обработка неудачного всплывающего окна

Когда popBackStack() возвращает false , последующий вызов NavController.getCurrentDestination() возвращает null . Это означает, что приложение извлекло последний пункт назначения из стека. В этом случае пользователь видит только пустой экран.

Это может произойти в следующих случаях:

  • popBackStack() ничего не извлекал из стека.
  • popBackStack() извлек пункт назначения из заднего стека, и теперь стек пуст.

Чтобы решить эту проблему, вам необходимо перейти к новому месту назначения или вызвать finish() в своей деятельности, чтобы завершить ее. Следующий фрагмент демонстрирует это:

котлин

...  if (!navController.popBackStack()) {     // Call finish() on your Activity     finish() } 

Ява

...  if (!navController.popBackStack()) {     // Call finish() on your Activity     finish(); } 

Всплывающее сообщение о пункте назначения

Чтобы удалить пункты назначения из заднего стека при переходе от одного пункта назначения к другому, добавьте аргумент popUpTo() к соответствующему вызову функции navigate() . popUpTo() инструктирует библиотеку навигации удалить некоторые пункты назначения из заднего стека как часть вызова navigate() . Значение параметра — это идентификатор пункта назначения в заднем стеке. Идентификатор может быть целочисленным id или строкой route .

Вы можете включить аргумент для inclusive параметра со значением true , чтобы указать, что пункт назначения, указанный вами в popUpTo() также должен выйти из стека.

Чтобы реализовать это программно, передайте popUpTo() в navigate() как часть NavOptions с inclusive значением true . Это работает как в Compose, так и в Views.

Сохранять состояние при появлении

Когда вы используете popUpTo для перехода к пункту назначения, вы можете дополнительно сохранить задний стек и состояния всех пунктов назначения, извлеченные из заднего стека. Затем вы сможете восстановить задний стек и пункты назначения при переходе к этому пункту назначения позднее. Это позволяет сохранять состояние для данного места назначения и иметь несколько обратных стеков .

Чтобы сделать это программно, укажите saveState = true при добавлении popUpTo к параметрам навигации.

Вы также можете указать restoreState = true в параметрах навигации, чтобы автоматически восстановить задний стек и состояние, связанное с пунктом назначения.

Например:

navController.navigate(     route = route,     navOptions =  navOptions {         popUpTo<A>{ saveState = true }         restoreState = true     } ) 

Чтобы включить сохранение и восстановление состояния в XML, определите popUpToSaveState как true и restoreState как true соответственно в соответствующем action .

XML-пример

Вот пример popUpTo в XML с использованием действия:

<action   android:id="@+id/action_a_to_b"   app:destination="@id/b"   app:popUpTo="@+id/a"   app:popUpToInclusive="true"   app:restoreState=”true”   app:popUpToSaveState="true"/> 

Пример создания

Ниже приведен полный пример того же самого в Compose:

@Composable fun MyAppNavHost(     modifier: Modifier = Modifier,     navController: NavHostController = rememberNavController(),     startDestination: Any = A ) {     NavHost(         modifier = modifier,         navController = navController,         startDestination = startDestination     ) {         composable<A> {             DestinationA(                 onNavigateToB = {                 // Pop everything up to, and including, the A destination off                 // the back stack, saving the back stack and the state of its                 // destinations.                 // Then restore any previous back stack state associated with                 // the B destination.                 // Finally navigate to the B destination.                     navController.navigate(route = B) {                         popUpTo<A> {                             inclusive = true                             saveState = true                         }                         restoreState = true                     }                 },             )         }         composable<B> { DestinationB(/* ... */) }     } }  @Composable fun DestinationA(onNavigateToB: () -> Unit) {     Button(onClick = onNavigateToB) {         Text("Go to A")     } } 

Более детально вы можете изменить способ вызова NavController.navigate() следующими способами:

// Pop everything up to the destination_a destination off the back stack before // navigating to the "destination_b" destination navController.navigate("destination_b") {     popUpTo("destination_a") }  // Pop everything up to and including the "destination_a" destination off // the back stack before navigating to the "destination_b" destination navController.navigate("destination_b") {     popUpTo("destination_a") { inclusive = true } }  // Navigate to the "search” destination only if we’re not already on // the "search" destination, avoiding multiple copies on the top of the // back stack navController.navigate("search") {     launchSingleTop = true } 

Общие сведения о передаче параметров в NavController.navigate() см. в руководстве «Навигация с параметрами» .

Поп с помощью действий

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

Дополнительное чтение

Для получения дополнительной информации прочитайте следующие страницы:

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

NavController содержит «обратный стек», содержащий пункты назначения, которые посетил пользователь. Когда пользователь перемещается по экранам вашего приложения, NavController добавляет и удаляет пункты назначения в заднем стеке и из него.

Будучи стеком, задний стек представляет собой структуру данных «последним пришел — первым ушел». Таким образом, NavController помещает элементы в верхнюю часть стека и извлекает их из нее.

Основное поведение

Вот основные факты, которые следует учитывать в отношении поведения обратного стека:

  • Первый пункт назначения: когда пользователь открывает приложение, NavController помещает первый пункт назначения в начало заднего стека.
  • Занесение в стек: каждый вызов NavController.navigate() помещает заданный пункт назначения в вершину стека.
  • Выдвижение верхнего пункта назначения: нажатие « Вверх» или «Назад» вызывает методы NavController.navigateUp() и NavController.popBackStack() соответственно. Они извлекают верхний пункт назначения из стека. См. страницу «Принципы навигации» для получения дополнительной информации о разнице между «Вверх» и «Назад» .

Вернитесь назад

Метод NavController.popBackStack() пытается извлечь текущий пункт назначения из заднего стека и перейти к предыдущему пункту назначения. Это эффективно перемещает пользователя на один шаг назад в истории навигации. Он возвращает логическое значение, указывающее, успешно ли он вернулся в пункт назначения.

Вернитесь к определенному пункту назначения

Вы также можете использовать popBackStack() для перехода к определенному пункту назначения. Для этого используйте одну из его перегрузок. Некоторые из них позволяют передавать идентификатор, например целочисленный id или строковый route . Эти перегрузки перенаправляют пользователя к месту назначения, связанному с данным идентификатором. Что особенно важно, они извлекают все, что находится в стеке выше этого пункта назначения.

Эти перегрузки также принимают inclusive логическое значение. Он определяет, должен ли NavController также извлечь указанный пункт назначения из заднего стека после перехода к нему.

Рассмотрим этот краткий фрагмент в качестве примера:

navController.popBackStack(R.id.destinationId, true) 

Здесь NavController возвращается в пункт назначения с целочисленным идентификатором destinationId . Поскольку значение inclusive аргумента равно true , NavController также извлекает указанный пункт назначения из заднего стека.

Обработка неудачного всплывающего окна

Когда popBackStack() возвращает false , последующий вызов NavController.getCurrentDestination() возвращает null . Это означает, что приложение извлекло последний пункт назначения из стека. В этом случае пользователь видит только пустой экран.

Это может произойти в следующих случаях:

  • popBackStack() ничего не извлекал из стека.
  • popBackStack() извлек пункт назначения из заднего стека, и теперь стек пуст.

Чтобы решить эту проблему, вам необходимо перейти к новому месту назначения или вызвать finish() в своей деятельности, чтобы завершить ее. Следующий фрагмент демонстрирует это:

котлин

...  if (!navController.popBackStack()) {     // Call finish() on your Activity     finish() } 

Ява

...  if (!navController.popBackStack()) {     // Call finish() on your Activity     finish(); } 

Всплывающее сообщение о пункте назначения

Чтобы удалить пункты назначения из заднего стека при переходе от одного пункта назначения к другому, добавьте аргумент popUpTo() к соответствующему вызову функции navigate() . popUpTo() инструктирует библиотеку навигации удалить некоторые пункты назначения из заднего стека как часть вызова navigate() . Значение параметра — это идентификатор пункта назначения в заднем стеке. Идентификатор может быть целочисленным id или строкой route .

Вы можете включить аргумент для inclusive параметра со значением true , чтобы указать, что пункт назначения, указанный вами в popUpTo() также должен выйти из стека.

Чтобы реализовать это программно, передайте popUpTo() в navigate() как часть NavOptions с inclusive значением true . Это работает как в Compose, так и в Views.

Сохранять состояние при появлении

Когда вы используете popUpTo для перехода к пункту назначения, вы можете дополнительно сохранить задний стек и состояния всех пунктов назначения, извлеченные из заднего стека. Затем вы сможете восстановить задний стек и пункты назначения при переходе к этому пункту назначения позднее. Это позволяет сохранять состояние для данного места назначения и иметь несколько обратных стеков .

Чтобы сделать это программно, укажите saveState = true при добавлении popUpTo к параметрам навигации.

Вы также можете указать restoreState = true в параметрах навигации, чтобы автоматически восстановить задний стек и состояние, связанное с местом назначения.

Например:

navController.navigate(     route = route,     navOptions =  navOptions {         popUpTo<A>{ saveState = true }         restoreState = true     } ) 

Чтобы включить сохранение и восстановление состояния в XML, определите popUpToSaveState как true и restoreState как true соответственно в соответствующем action .

XML-пример

Вот пример popUpTo в XML с использованием действия:

<action   android:id="@+id/action_a_to_b"   app:destination="@id/b"   app:popUpTo="@+id/a"   app:popUpToInclusive="true"   app:restoreState=”true”   app:popUpToSaveState="true"/> 

Пример создания

Ниже приведен полный пример того же самого в Compose:

@Composable fun MyAppNavHost(     modifier: Modifier = Modifier,     navController: NavHostController = rememberNavController(),     startDestination: Any = A ) {     NavHost(         modifier = modifier,         navController = navController,         startDestination = startDestination     ) {         composable<A> {             DestinationA(                 onNavigateToB = {                 // Pop everything up to, and including, the A destination off                 // the back stack, saving the back stack and the state of its                 // destinations.                 // Then restore any previous back stack state associated with                 // the B destination.                 // Finally navigate to the B destination.                     navController.navigate(route = B) {                         popUpTo<A> {                             inclusive = true                             saveState = true                         }                         restoreState = true                     }                 },             )         }         composable<B> { DestinationB(/* ... */) }     } }  @Composable fun DestinationA(onNavigateToB: () -> Unit) {     Button(onClick = onNavigateToB) {         Text("Go to A")     } } 

Более детально вы можете изменить способ вызова NavController.navigate() следующими способами:

// Pop everything up to the destination_a destination off the back stack before // navigating to the "destination_b" destination navController.navigate("destination_b") {     popUpTo("destination_a") }  // Pop everything up to and including the "destination_a" destination off // the back stack before navigating to the "destination_b" destination navController.navigate("destination_b") {     popUpTo("destination_a") { inclusive = true } }  // Navigate to the "search” destination only if we’re not already on // the "search" destination, avoiding multiple copies on the top of the // back stack navController.navigate("search") {     launchSingleTop = true } 

Общие сведения о передаче параметров в NavController.navigate() см. в руководстве «Навигация с параметрами» .

Поп с помощью действий

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

Дополнительное чтение

Для получения дополнительной информации прочитайте следующие страницы:

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