以降のセクションでは、バックスタックを保存し、バックスタックのエントリに関連付けられた状態を保存するための戦略について説明します。
バックスタックを保存する
構成の変更やプロセスの終了など、さまざまなライフサイクル イベントでアプリのナビゲーション状態が維持されるようにすることは、優れたユーザー エクスペリエンスを実現するために不可欠です。Navigation
3 では、バックスタックはユーザーが所有するため、バックスタックの作成方法や保存方法に関する厳格なガイドラインはありません。ただし、Navigation 3 には、保存可能なバックスタックを提供する便利なメソッドが用意されています:
rememberNavBackStack。
rememberNavBackStack を使用する
rememberNavBackStack コンポーズ可能な関数は、構成の変更やプロセスの終了後も維持されるバックスタックを作成するように設計されています。
rememberNavBackStack が正しく機能するためには、バックスタック内の各キーが特定の要件を満たしている必要があります。
NavKeyインターフェースを実装する: バックスタック内のすべてのキーは、NavKeyインターフェースを実装する必要があります。これは、キーを保存できることをライブラリに通知するマーカー インターフェースとして機能します。@Serializableアノテーションを付ける:NavKeyを実装するだけでなく、 キーのクラスとオブジェクトに@Serializableアノテーションを付ける必要があります。
次のスニペットは、rememberNavBackStack の正しい実装を示しています。
@Serializable data object Home : NavKey @Composable fun NavBackStack() { val backStack = rememberNavBackStack(Home) }
NavKey のサブタイプを使用してバックスタックを保存する
rememberNavBackStack コンポーズ可能な関数は NavBackStack<NavKey> を返します。
アプリが独自の NavKey サブタイプを定義し、すべてのキーがそのサブタイプを継承している場合は、次のようにカスタムの保存関数を実装して、その型を保持できます。
@Serializable sealed interface MyAppNavKey : NavKey @Serializable data object ScreenA: MyAppNavKey @Serializable data class ScreenB(val id: String): MyAppNavKey @Composable fun rememberMyAppNavBackStack(vararg elements: MyAppNavKey): NavBackStack<MyAppNavKey> { return rememberSerializable(serializer = serializer()) { NavBackStack(*elements) } } @Composable fun MyApp() { // defaultNavBackStack is NavBackStack<NavKey> val defaultNavBackStack = rememberNavBackStack(ScreenA) // myAppNavBackStack is NavBackStack<MyAppNavKey> val myAppNavBackStack = rememberMyAppNavBackStack(ScreenA) }
オープン ポリモーフィズムの処理方法など、その他の例については、
NavBackStackSamples をご覧ください。
代替方法: ViewModel に保存する
バックスタックを管理する別の方法として、ViewModel に保存する方法があります。ViewModel
または他のカスタム ストレージを使用する場合に、プロセスの終了後も永続化するには、次の操作を行う必要があります。
- キーがシリアル化可能であることを確認する:
rememberNavBackStackと同様に、 ナビゲーション キーはシリアル化可能である必要があります。 - シリアル化と逆シリアル化を手動で処理する: アプリがバックグラウンドに移行する場合や復元される場合は、各キーのシリアル化された表現を永続ストレージ(
SharedPreferences、 データベース、ファイルなど)に手動で保存し、そこから逆シリアル化する必要があります。
ViewModel を NavEntry にスコープ設定する
ViewModels は、画面の回転などの構成変更後も UI 関連の状態を保持するために使用されます。デフォルトでは、ViewModels は最も近い ViewModelStoreOwner(通常は Activity または Fragment)にスコープ設定されます。
ただし、ViewModel を Activity 全体ではなく、バックスタック上の特定の NavEntry(特定の画面または宛先)にスコープ設定することもできます。これにより、ViewModel の状態は、その特定の NavEntry がバックスタックの一部である間のみ保持され、NavEntry がポップされるとクリアされます。
androidx.lifecycle:lifecycle-viewmodel-navigation3 アドオン ライブラリには、これを容易にする
NavEntryDecorator が用意されています。このデコレータは、各 NavEntry に ViewModelStoreOwner を提供します。NavEntry のコンテンツ内に ViewModel を作成すると(Compose で viewModel() を使用するなど)、バックスタック上のその特定の NavEntry のキーに自動的にスコープ設定されます。つまり、ViewModel は NavEntry がバックスタックに追加されるときに作成され、削除されるときにクリアされます。
NavEntryDecorator を使用して ViewModel を NavEntry にスコープ設定する手順は次のとおりです。
androidx.lifecycle:lifecycle-viewmodel-navigation3依存関係をapp/build.gradle.ktsファイルに追加します。- デフォルトの
rememberSaveableStateHolderNavEntryDecorator()をentryDecoratorsのリストにNavDisplayを構築するときに追加します。 rememberViewModelStoreNavEntryDecorator()をentryDecoratorsのリストに追加します。
NavDisplay( entryDecorators = listOf( // Add the default decorators for managing scenes and saving state rememberSaveableStateHolderNavEntryDecorator(), // Then add the view model store decorator rememberViewModelStoreNavEntryDecorator() ), backStack = backStack, entryProvider = entryProvider { }, )