NavController
が「バックスタック」を保持するユーザーがクリックすると、
確認できます。ユーザーがアプリ内で画面移動すると、NavController
は、バックスタックとの間でデスティネーションを追加または削除します。
スタックであるバックスタックは「後入れ先出し」学びました。「
そのため、NavController
はアイテムを一番上にプッシュし、上部からアイテムをポップします。
説明します。
基本的な動作
バックスタックの動作については、次の点に注意してください。
- 最初のデスティネーション: ユーザーがアプリを開くと、
NavController
は最初のデスティネーションをバックスタックの一番上にプッシュします。 - スタックへのプッシュ:
NavController.navigate()
が呼び出されるたびに、特定のデスティネーションがスタックの一番上にプッシュされます。 - 最上部のデスティネーションをポップする: [上へ] または [戻る] をタップすると、
NavController.navigateUp()
メソッドとNavController.popBackStack()
メソッドがそれぞれ呼び出され、スタックの最上部にあるデスティネーションがポップされます。[上へ] と [戻る] の違いについて詳しくは、ナビゲーションの原則のページをご覧ください。
ポップバック
NavController.popBackStack()
メソッドでは、バックスタックから現在のデスティネーションがポップされ、前のデスティネーションへの移動が行われます。これにより、ユーザーは実質的にナビゲーション履歴内の 1 つ前のステップに戻ることができます。このメソッドでは、正常にポップされてデスティネーションに戻ったかどうかを示すブール値が返されます。
特定のデスティネーションにポップバックする
popBackStack()
を使用して特定のデスティネーションに移動することもできます。これを行うには、そのオーバーロードの一つを使用します。整数の id
や文字列の route
など、識別子を渡すことができるものがいくつかあります。これらのオーバーロードにより、指定された識別子に関連付けられたデスティネーションにユーザーを誘導します。重要なのは、スタック内のそのデスティネーションの上にあるすべてをポップすることです。
これらのオーバーロードは、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()
は、navigate()
の呼び出しの一部として、バックスタックから一部のデスティネーションを削除するよう Navigation ライブラリに指示します。パラメータ値は、バックスタック上のデスティネーションの識別子です。識別子は、整数 id
または文字列 route
のいずれかです。
inclusive
パラメータの引数に true
を指定して、popUpTo()
で指定したデスティネーションもバックスタックからポップするように指定することもできます。
これをプログラムで実装するには、inclusive
を true
に設定した NavOptions
の一部として、popUpTo()
を navigate()
に渡します。これは Compose とビューの両方で機能します。
ポップアップ時に状態を保存する
popUpTo
を使用してデスティネーションに移動する場合、必要に応じて
バックスタックからポップされたすべてのデスティネーションの状態を表します。Google Chat では
次に、そのデスティネーションに移動したときに、バックスタックとデスティネーションを復元します。
できます。これにより、特定のデスティネーションの状態を保持し、
複数のバックスタックを使用できます。
これをプログラムで行うには、popUpTo
をプログラムに追加するときに、saveState = true
を指定します。
ナビゲーション オプションが表示されます。
ナビゲーション オプションで restoreState = true
を指定して、
関連する状態が自動的に復元され、バックスタックが
あります。
例:
navController.navigate(
route = route,
navOptions = navOptions {
popUpTo<A>{ saveState = true }
restoreState = true
}
)
XML で状態の保存と復元を有効にするには、popUpToSaveState
を true
として定義します。
関連付けられた action
で、restoreState
をそれぞれ true
として使用します。
XML の例
action を使用した 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: 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()
にオプションを渡す方法については、オプションでの移動ガイドをご覧ください。
アクションを使用してポップする
アクションを使用して移動する場合、必要に応じて、追加のデスティネーションをバックスタックからポップできます。たとえば、アプリに初期ログインフローがある場合、一度ユーザーがログインした後は、[戻る] ボタンをタップしてもログインフローに戻ることがないように、ログイン関連デスティネーションをすべてバックスタックからポップする必要があります。
その他の情報
詳しくは、以下のページをご覧ください。
- 循環型ナビゲーション: ナビゲーション フローが循環型の場合に、バックスタックが過剰にならないようにする方法を説明します。
- ダイアログ デスティネーション: ダイアログ デスティネーションにより、バックスタックの管理方法に独自の考慮事項が含まれるようになる点について説明します。