[使用Jetpack导航时,我们可以使用popUpTo
和popInclusive
清除堆栈。但是当我不知道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”。
我有办法知道哪个目的地是最低的,所以我可以弹出它并清除堆栈?
据我所知,没有简单而优美的方法来获得您想要达到的目标。不过,有一些可能的解决方案。
您可能有一个始终位于堆栈底部的基本目标,我们称它为baseDest
。在需要清除堆栈的操作中,您可以随时使用
<action
android:id="..."
app:destination="@id/mainDestX"
app:popUpTo="@+id/baseDest"
app:popUpToInclusive="false" />
这将始终将baseDest保留在堆栈的底部,使您始终可以弹出它。要在您的主要目的地之一上实现反压行为,您可以:
onBackPressed
方法以关闭应用程序。 (如果您的所有主要目标都来自同一类,则可以轻松完成)也许您应该重新考虑应用程序中导航的工作方式。与其具有某种可能的循环图结构,不如处理树状导航结构(用户也可以更直观地理解它们)。当然,这并不总是一种选择,但是您应该牢记这一点,并考虑重新构造导航。
手动执行所有操作和导航,并使用NavController中提供的方法,在导航到您的主要目的地之一之前,手动删除堆栈中的所有条目。为此,一种可行的方法是使用片段中的findNavController方法来检索导航控制器。我尚未测试以下任何一种方法,但是您可以尝试:
yourNavController.getGraph().clear()
,然后再执行yourNavController.navigate(yourDest)
saved = yourNavController.saveState()
,并在导航到您的mainDestinations之一时使用yourNavController.restoreState(saved)
,再次在后跟yourNavController.navigate(yourDest)
yourNavController.setGraph(createdGraph)
我找不到解决该问题的任何官方解决方案,但这是一种对我有用的方法:
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)
}