意外と知られていない気がするので、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を実装する感じになります。詳細は以下の公式ドキュメントにまとまっています。実装自体は単純です。