ViewModelの初期化時にFragmentから値を渡したいときにAssistedInjectを使いますが、ボイラープレートが増えてしまって非常に煩わしかったりします。そんなとき、以下のExtensionを作ると非常に便利です。
inline fun <reified T : ViewModel> Fragment.assistedViewModel(
crossinline viewModelProducer: (SavedStateHandle) -> T
) = viewModels<T> {
@Suppress("UNCHECKED_CAST")
object : AbstractSavedStateViewModelFactory(this, arguments) {
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
) = viewModelProducer(handle) as T
}
}
使い方は簡単でVewModelにFacotryを定義しつつ、上記Extensionを使ってInjectする感じです。
HogeFragment.kt
@AndroidEntryPoint
class HogeFragment : Fragment() {
@Inject
lateinit var factory: HogeViewModel.Factory
private val viewModel: HogeViewModel by assistedViewModel {
factory.create(it)
}
}
HogeViewModel.kt
class HogeViewModel @AssistedInject constructor(
@Assisted private val savedState: SavedStateHandle
) : ViewModel() {
@AssistedFactory
interface Factory {
fun create(savedState: SavedStateHandle): HogeViewModel
}
}
argmentsの値を渡したいときでもFactoryのcreate関数をよしなに書けばうまく動かせます。
Hilt便利!!!