Navigation ComposeとParcelable

Kenji Abe
Feb 3, 2022
Photo by israel palacio on Unsplash

Navigation Composeの引数にて単純にParcelableのような複雑なデータを扱うことはできないですが、とはいえ次の画面に複雑なデータを渡したいことはよくあります。
そういう場合の実装方法について3パターン紹介します。

データレイヤーで解決する

まず1つ目の方法ですが、Androidチームが推奨している方法になります。画面遷移ではデータ自体を渡すのではなく、データを参照できるようなIDなどを渡して取得する感じですね。

ドキュメントには複雑なデータを渡すのはアンチパターンとして記載されています。(とはいえ、データ渡したいですよね…)

Caution: Passing complex data structures over arguments is considered an anti-pattern. Each destination should be responsible for loading UI data based on the minimum necessary information, such as item IDs. This simplifies process recreation and avoids potential data inconsistencies.

例として一覧画面から詳細画面を表示するようなケースですは、一覧からはIDを渡して、詳細画面でそのIDを使ってデータを再取得する感じになります。

IDで取得するようなAPIが提供されていない場合などで単純に再取得が出来ない場合は、メモリキャッシュなどを活用する必要があります。

設計ガイドでメモリキャッシュについての実装があるのでそちらも参考にする良いと思います。(ドキュメント

共有ViewModelを使う

ViewModelをComposeの画面間で共有することで、データを受け渡す方法です。

ViewModelを画面間で共有するには親となるViewModelStoreOwnerを指定する必要があります。以下のような関数を作っておくと良いと思います。

あとは、ViewModelStoreOwner指定すればViewModelを共有することが可能です。

この実装での問題点としては共有するViewModelが生存期間が長くなり、使用しない画面でも生存している状態になります。

この生存期間が長い問題は、NavGraphをネストすることで対応することができます。

この実装については、StackOverflowにてGoogleのIan氏の回答を参考にしています。

カスタムNavTypeを使う

最後に紹介する方法として、カスタムNavTypeを使うパターンです。

まずは以下のような感じでカスタムNavTypeを定義します。この例では実態としてJSONを使って受け渡す感じになります。

次にNavGraphの定義と値を渡す側の実装です。

渡すときはJSONに変換してあげる必要がありますが、受け取るときは Parcelable として受け取ることが可能になります。

カスタムNavTypeについては以下のドキュメントを参考にしてください。

https://developer.android.com/guide/navigation/navigation-kotlin-dsl#custom-types

--

--

Kenji Abe

Programmer / Gamer / Google Developers Expert for Android, Kotlin / @STAR_ZERO