Photo by Zoya Loonohod on Unsplash

意外と知られていない気がするので、ViewModelで画面引数を受け取る方法をまとめておきます。

AssistedInjectなどの特殊なことも必要なく、かなり簡単にViewModelで画面引数を受け取れます。

受け取る方法

実はViewModelで画面引数を受け取るには非常に簡単で、以下のように SavedStateHandle から取得できます。

class SampleViewModel(
savedStateHandle: SavedStateHandle
) : ViewModel() {

val userId: String? = savedStateHandle["userId"]

// ...
}

ViewModelのコンストラクタで SavedStateHandle を受け取るようにしておくと、画面引数として渡したときと同じキーを使うだけ取得できます。

渡す方法

画面引数を渡す方法に特別なことは不要で、ActivityのIntent、Navigation Component、Navigation Compose、どの渡し方でも SavedStateHandle で取得することができます。

// Activity Intent
val intent = Intent(this, SampleActivity::class.java).apply {
putExtra("userId", "xxxx")
}
startActivity(intent)


// Navigation Component
val action = SampleFragmentDirections.action("xxxx")
findNavController().navigate(action)


// Navigation Compose
NavHost(navController = navController, startDestination = "start") {
composable("start") {
HomeScreen(
onClick = { navController.navigate("sample/xxxx") }
)
}
composable("sample/{userId}") {
// ...
}
}

Safe Args対応

Navigation Componentを使ってるときにSafe Argsを使うことが多いと思いますが、SavedStateHandle から引数を取得するときにもSafe Argsのクラスに変換することが可能です。 fromSavedStateHandle というヘルパーメソッドが生成されるので、それを使うだけで簡単に対応することができます。

class SampleViewModel(
savedStateHandle: SavedStateHandle
) : ViewModel() {

val args = SampleFragmentArgs.fromSavedStateHandle(savedStateHandle)

// ...
}

Navigation ComposeのType Safe対応

Navigation Composeを使ってる場合は自分でWrapperを実装する感じになります。詳細は以下の公式ドキュメントにまとまっています。実装自体は単純です。

--

--

Photo by Possessed Photography on Unsplash

Composeの画面遷移で、前の画面に結果を返す方法についてまとめておきます。

基本的にはFragmentと同じような感じで NavBackStackEntrySavedStateHandle を使用していきます。

結果を返す

ScreenAからScreenBに遷移して、ScreenBでの画面の結果をScreenAに返す処理です。

navController …

--

--

Photo by Tobias Cornille on Unsplash

Composeにおいてrecomposition後も状態を保持するために remember がありますが、画面回転などConfiguration Change後でも状態を保持する rememberSaveable について解説します。

rememberSaveable

単純な値で rememberSaveable を使う場合は remember とほぼ変わりません。

また、 mutableStateOf も同様に使用できます。

これだけでConfiguration Change後も値を復元してくれます。

使用できる型

rememberSaveable はすべての型が使用できるわけではありません。

例えば、上記のように独自のクラスを rememberSaveable で使おうとすると、以下の例外を投げます。

java.lang.IllegalArgumentException: User(name=) cannot be saved using the current SaveableStateRegistry. The default implementation only supports types which can be stored inside the Bundle. Please consider implementing a custom Saver for this class and pass it to rememberSaveable().

rememberSaveable は最終的に ComponentActivity#onSaveInstanceState にて状態を保存するため、 Bundle に保存できるもだけが使用できます。

サポートされてる型は ココのコード で定義されています。
また、MutableState については特別な処理で対応していて、MutableStateで使われてる型のほうがチェックされます。

rememberSaveable に対応する

rememberSaveable に対応するにはいくつかの方法があります。

Parcelable

一番簡単な方法は、独自クラスを Parcelable にするだけです。

これでクラッシュせず rememberSaveable でも使用可能になります。

Saverの実装

単純に Parcelable に対応できない場合は Saver を実装することで対応することもできます。

SaverBundle に保存できる型に変換して、Bundle から復元した値を変換する処理を実装します。 実装したものをrememberSaveablesaver パラメータに渡すことで対応できます。

MutableState を使う場合は stateSaver パラメータのほうに実装した Saver を渡します。

--

--

Photo by Nick Fewings on Unsplash

Android 13からOpt inにて Predictive back gesture が使用できるようになります。これにより、バックジェスチャー(画面の左から右にスワイプするやつ)でホームに戻るときに予測できるようになります。

どのような感じは以下のドキュメントで確認できます。戻るときにホーム画面が少し見えるような感じになります。

https: …

--

--

Photo by Carolina Garcia Tavizon on Unsplash

Material 3のColor Systemには Surface tones というものがあります。この仕様によって想定した色をうまく設定できないなど気づきにくいこともあります。この Surface tones についてComposeの実装を踏まえて簡単にまとめておきます。

これ書いてる時点ではCompose Material 3はalphaなので今 …

--

--

Kenji Abe

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