NavController
會保留包含使用者已造訪目的地的「返回堆疊」。當使用者在整個應用程式中瀏覽畫面時,NavController
會在返回堆疊中新增及移除目的地。
做為堆疊,返回堆疊是採用「後進先出」的資料結構。因此 NavController
會將項目推送至堆疊頂端,並從堆疊頂端彈出項目。
基本行為
針對返回堆疊的行為,您應考量以下核心事實:
- 第一個目的地:使用者開啟應用程式時,
NavController
會將第一個目的地推送至返回堆疊頂端。 - 推送至堆疊:每次呼叫
NavController.navigate()
,都會將指定的目的地推送至堆疊頂端。 - 彈出頂端目的地:輕觸「向上」或「返回」,即可分別呼叫
NavController.navigateUp()
和NavController.popBackStack()
方法。這些方法會彈出堆疊頂端的目的地。請參閱「導覽原則」頁面,進一步瞭解「向上」和「返回」的差異。
彈回
NavController.popBackStack()
方法會嘗試彈出返回堆疊中目前的目的地,並前往上一個目的地。這樣就能有效將使用者導向導覽記錄中的上一個位置。這個方法會傳回布林值,表示是否已成功彈回該目的地。
彈回特定目的地
您也可以使用 popBackStack()
前往特定目的地,方法是使用其中一個超載。您可以透過多個超載傳入 ID,例如整數 id
或字串 route
。這些超載會將使用者導向與指定 ID 相關聯的目的地。重要的是,這些超載會彈出該目的地上方的所有堆疊項目。
這些超載也包含 inclusive
布林值,可決定 NavController
是否應在前往指定目的地後,從返回堆疊中彈出該目的地。
請參考以下簡短的程式碼片段範例:
navController.popBackStack(R.id.destinationId, true)
這裡的 NavController
會彈回目的地,整數 ID 為 destinationId
。由於 inclusive
引數的值為 true
,NavController
也會彈出返回堆疊中的指定目的地。
處理失敗的彈回
popBackStack()
傳回 false
時,對 NavController.getCurrentDestination()
的後續呼叫會傳回 null
。這表示應用程式已彈出返回堆疊中的最後一個目的地。在這種情況下,使用者只會看到空白畫面。
這可能發生於下列情況:
popBackStack()
未彈出任何堆疊項目。popBackStack()
已彈出返回堆疊中的目的地,堆疊現為空白。
如要解決這個問題,您必須前往新目的地,或在活動中呼叫 finish()
以結束活動。請參考下列程式碼片段:
Kotlin
...
if (!navController.popBackStack()) {
// Call finish() on your Activity
finish()
}
Java
...
if (!navController.popBackStack()) {
// Call finish() on your Activity
finish();
}
彈出至目的地
從一個目的地導覽至另一個目的地時,如要移除返回堆疊中的目的地,請在相關聯的 navigate()
函式呼叫中加入 popUpTo()
引數。popUpTo()
會指示 Navigation 程式庫在呼叫 navigate()
時,移除返回堆疊中的某些目的地。參數值是返回堆疊中目的地的 ID。ID 可以是整數 id
或字串 route
。
您可以在 inclusive
參數中加入值為 true
的引數,指出您在 popUpTo()
中指定的目的地也應從返回堆疊中彈出。
如要以程式輔助方式實作,請在 NavOptions
中將 popUpTo()
傳遞至 navigate()
,並將 inclusive
設為 true
。這適用於 Compose 和 View。
在彈出時儲存狀態
使用 popUpTo
前往目的地時,您可以視需要儲存所有從返回堆疊中彈出的目的地狀態。
如要啟用這個選項,請在相關聯的 action
或對 NavController.navigate()
的呼叫中,將 popUpToSaveState
定義為 true
。
您前往目的地時,也可以將 restoreSaveState
定義為 true
,即可自動還原 destination
屬性中與目的地相關聯的狀態。
XML 範例
以下是 XML 中使用動作的 popUpTo
範例:
<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 範例
以下是 Compose 中相同的完整範例:
@Composable
fun MyAppNavHost(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
startDestination: String = "destination_a"
) {
NavHost(
modifier = modifier,
navController = navController,
startDestination = startDestination
) {
composable("destination_a") {
DestinationA(
onNavigateToB = {
// 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") {
inclusive = true
saveState = true
}
}
},
)
}
composable("destination_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()
的一般資訊,請參閱「使用選項導覽」指南。
使用動作彈出
使用操作進行瀏覽時,可以選擇從返回堆疊外關閉其他目的地。舉例來說,如果您的應用程式有起始的登入流程,當使用者登入時,請將所有與登入相關的目的地都從返回堆疊中彈出,讓「返回」按鈕不會將使用者導回登入流程。
延伸閱讀
如需詳細資訊,請參閱以下頁面: