google / dagger

A fast dependency injector for Android and Java.
https://dagger.dev
Apache License 2.0
17.41k stars 2.01k forks source link

Hilt - Support providing an abstract type as key for @HiltViewModel #3473

Closed prashanOS closed 2 years ago

prashanOS commented 2 years ago

Currently, dependency inversion is not possible for @HiltViewModel-annotated ViewModels. Callers must declare the exact concrete implementation:

class ConcreteViewModel : ViewModel()

val viewModel: ConcreteViewModel = viewModel()

Ideally, we'd be able to do something like this:

interface ViewModelInterface

@HiltViewModel(keyType = ViewModelInterface::class)
class RealViewModel : ViewModel(), ViewModelInterface

val viewModel: ViewModelInterface = viewModel()

Even ignoring the use case of providing different implementations via DI, it is useful to be able to split interfaces from their implementations.

danysantiago commented 2 years ago

This is not possible because the various ViewModel APIs all declare type variables with a bound type, i.e. T extends ViewModel, so it is not possible to return an interface that just describes a ViewModel. See for example ViewModelProvider.get().

prashanOS commented 2 years ago

Sure, but you could still define an abstract class that extends ViewModel, right?

Chang-Eric commented 2 years ago

Thanks for the suggestion, but I don't think we really want to do this because Hilt's approach to Android is generally to be as minimal as possible and try not to add too many features or concepts over the Android API. We're usually willing to consider something like this more in Dagger because we can control basically the whole thing for how to construct a regular object, but I don't really want to try to add something like this across the Android APIs.

Also, in this case, this API that is similar to @Binds probably would be used for faking or mocking the ViewModel (ignoring the fact that that would need another feature request to uninstall other ViewModel to key bindings or allow a binding to a key interface to be used instead). Our general stance on that is that we don't encourage replacing Android constructs like Activity, Fragment, or ViewModel, but rather that those should be used with the real thing and the Dagger bindings within them should be replaced.

I'm going to close this issue, but hopefully that explanation makes sense, thanks!