【Jetpack Compose Navigation3】EntryDecorator と ViewModel の「key」の深い関係

Jetpack Compose の Navigation3 では、画面遷移の引数として RouteB(val id: String) のようなデータクラスを渡します。

このとき、同じ RouteB でも id が違えば「別の画面(別の ViewModel)」として扱いたいですよね。

ここで重要になるのが EntryDecoratorviewModel(key = ...) の関係です。

 

🤔 結論:Decorator が「鍵」を管理してくれるか否か

一言でいうと、こうなります。

Decorator を使わない場合:
手動で viewModel(key = "unique_id") を指定する必要がある。

Decorator を使えば:
viewModel() の引数は不要。
Decorator が自動で各エントリに個別の ViewModelStore を割り当ててくれる。

 

🤔 1. Decorator を使わないパターン(手動管理)

Navigation3 の基本機能 NavDisplay を使う場合、ViewModel の生存期間はデフォルトの「Activity 全体」に紐づきます。

同じ RouteB でも id ごとに ViewModel を作り分けたい場合、以下のように手動で key を渡して、内部のキャッシュを分ける必要があります。


entry<RouteB> { key ->
    // key(RouteBのインスタンス)の id を使って、ViewModelを区別する
    val vm = viewModel(
        key = key.id, // ← これが必要!
        factory = RouteBViewModel.Factory(key)
    )
    ScreenB(vm)
}

これを忘れると、id = "1" の画面から id = "2" の画面へ遷移しても、同じ ViewModel インスタンスが使い回されてしまい、表示内容が更新されない というバグに繋がります。

 

🤔 2. Decorator を使うパターン(Navigation3 の推奨)

サンプルの BasicViewModelsActivity で採用されている方法です。

NavDisplay の設定に rememberViewModelStoreNavEntryDecorator() を追加します。


NavDisplay(
    backStack = backStack,
    entryDecorators = listOf(
        rememberSaveableStateHolderNavEntryDecorator(),
        rememberViewModelStoreNavEntryDecorator() // ← これが魔法のスパイス
    ),
    entryProvider = entryProvider {
        entry<RouteB> { key ->
            // key 指定が不要になる!
            val vm = viewModel(factory = RouteBViewModel.Factory(key))
            ScreenB(vm)
        }
    }
)

なぜ key が不要になるのか?

ViewModelStoreNavEntryDecorator は、バックスタックにある 「各エントリ(NavEntry)」ごとに独立した ViewModelStore を生成してくれます。

RouteB("1") のエントリ ➔ 専用の ViewModelStore A が用意される

RouteB("2") のエントリ ➔ 専用の ViewModelStore B が用意される

viewModel() 関数は、その時点の LocalViewModelStoreOwner(Decorator が提供するエントリごとのストア)を参照します。そのため、わざわざ key を指定しなくても、エントリが違えば自動的に別の ViewModel が作られる仕組みです。

 

🤔 まとめ:どっちを使うべき?

基本的には「Decorator を使う」のが正解です。

理由1:
コードがシンプルになる(key の指定漏れがなくなる)。

理由2:
画面を戻ったときに ViewModel が正しく破棄されるなど、ライフサイクル管理が Navigation3 のエントリと完全に同期する。

「この画面だけは特殊な管理をしたい」という場合を除き、rememberViewModelStoreNavEntryDecorator() をセットアップして、型安全な key をそのまま Factory に渡すスタイルを基本にしましょう。


Related Categories :  AndroidJetpackComposeKMPKotlinKotlin Multiplatform MobileRecommendedReputationReviewTrending