导航组件:跳转到动态根目录并清除后退堆栈

问题描述 投票:0回答:2

[使用Jetpack导航时,我们可以使用popUpTopopInclusive清除堆栈。但是当我不知道popUpto的目标位置时如何清除堆栈?

示例

说我有3个主要目的地,到达目的地时应该有一个清晰的栈。每个主要目的地都有自己的屏幕流(可以通过深度链接直接访问)。

假设导航在这里向下流动:

Start app:
 - Main Dest 1 (nav to dest 2)
     - Dest 2 (nav to dest 3)
         - Dest 3 (nav to main dest 2)
            --clear--
 - (with clear stack)
   Main Dest 2 (nav to dest 4)
     - Dest 4 (nav to main dest 3)
         --clear-->
 - (with clear stack)
   Main Dest 3
 - Back button should close the app here

由于导航非常动态,因此我无法保证根目录的目的地。例如,即使我可以弹出“ Main Dest 2”,我也不知道它在堆栈中,因为我可能直接从URL转到“ Dest 4”。

我有办法知道哪个目的地是最低的,所以我可以弹出它并清除堆栈?

android kotlin android-jetpack android-jetpack-navigation
2个回答
0
投票

据我所知,没有简单而优美的方法来获得您想要达到的目标。不过,有一些可能的解决方案。


使用某种基本片段

您可能有一个始终位于堆栈底部的基本目标,我们称它为baseDest。在需要清除堆栈的操作中,您可以随时使用

<action
    android:id="..."
    app:destination="@id/mainDestX"
    app:popUpTo="@+id/baseDest"
    app:popUpToInclusive="false" />

这将始终将baseDest保留在堆栈的底部,使您始终可以弹出它。要在您的主要目的地之一上实现反压行为,您可以:

  1. 在所有主要目标中覆盖onBackPressed方法以关闭应用程序。 (如果您的所有主要目标都来自同一类,则可以轻松完成)
  2. 当由于反压而加载baseDest片段时,以编程方式关闭应用程序。

重新考虑您的应用导航

也许您应该重新考虑应用程序中导航的工作方式。与其具有某种可能的循环图结构,不如处理树状导航结构(用户也可以更直观地理解它们)。当然,这并不总是一种选择,但是您应该牢记这一点,并考虑重新构造导航。


以编程方式找到解决方案

手动执行所有操作和导航,并使用NavController中提供的方法,在导航到您的主要目的地之一之前,手动删除堆栈中的所有条目。为此,一种可行的方法是使用片段中的findNavController方法来检索导航控制器。我尚未测试以下任何一种方法,但是您可以尝试:

  1. 先执行yourNavController.getGraph().clear(),然后再执行yourNavController.navigate(yourDest)
  2. 在加载任何片段之前,在应用程序的开头使用saved = yourNavController.saveState(),并在导航到您的mainDestinations之一时使用yourNavController.restoreState(saved),再次在后跟yourNavController.navigate(yourDest)
  3. 创建新的NavGraph并使用yourNavController.setGraph(createdGraph)

0
投票

我找不到解决该问题的任何官方解决方案,但这是一种对我有用的方法:

private val mBackStackField by lazy {
  val field = NavController::class.java.getDeclaredField("mBackStack")
  field.isAccessible = true
  field
}

fun popToRoot(navController: NavController) {
  val arrayDeque = mBackStackField.get(navController) as java.util.ArrayDeque<NavBackStackEntry>
  val graph = arrayDeque.first.destination as NavGraph
  val rootDestinationId = graph.startDestination

  val navOptions = NavOptions.Builder()
    .setPopUpTo(rootDestinationId, false)
    .build()

  navController.navigate(rootDestinationId, null, navOptions)
}
© www.soinside.com 2019 - 2024. All rights reserved.