To retrieve the ViewModel from the component without Map Multibinding, you can do:
@Singleton
@Component(modules=[...])
interface SingletonComponent {
val aboutListViewModel: Provider<AboutListViewModel>
}
Which works when you can use @Inject constructor
:
// unscoped
class AboutListViewModel @Inject constructor(): ViewModel() {
}
Because now you can do:
class AboutListFragment: Fragment(R.layout.about_list_fragment) {
private val viewModel by viewModels<AboutListViewModel>() {
object: ViewModelProvider.Factory {
override fun create(clazz: Class<ViewModel>) {
return (requireActivity().application as MyApplication).component.aboutListViewModel.get()
}
}
}
}
Which might seem tacky, but you can hide all of that in an extension function
fun <T: ViewModel> Fragment.fragmentViewModels(viewModelCreator: SingletonComponent.() -> T) = viewModels<T> {
object: ViewModelProvider.Factory {
override fun create(clazz: Class<ViewModel>) {
val component = requireActivity().application as MyApplication).component
return viewModelCreator(component)
}
}
}
Because now you can do
class AboutListFragment: Fragment(R.layout.about_list_fragment) {
private val viewModel by fragmentViewModels<AboutListViewModel> { component ->
component.aboutListViewModel().get()
}
}
And this would work even without map multibinding. If you need a SavedStateHandle
, you'd need AssistedInject, but if you don't want that, it'll be easier when Dagger-Hilt is stable (then it'll be as simple as @ViewModelInject
and @Assisted
).