I am following this documentation to learn about LiveData and ViewModel. In the doc, the ViewModel class has constructor as such,
public class UserModel extends ViewModel {
private MutableLiveData<User> user;
@Inject UserModel(MutableLiveData<User> user) {
this.user = user;
}
public void init() {
if (this.user != null) {
return;
}
this.user = new MutableLiveData<>();
}
public MutableLiveData<User> getUser() {
return user;
}
}
However, when I run the code, I get exception:
final UserViewModelviewModel = ViewModelProviders.of(this).get(UserViewModel.class);
Caused by: java.lang.RuntimeException: Cannot create an instance of class UserViewModel Caused by: java.lang.InstantiationException: java.lang.Class has no zero argument constructor
While initializing subclasses of
ViewModel
usingViewModelProviders
, by default it expects yourUserModel
class to have zero argument constructor. In your case your constructor has argumentMutableLiveData<User> user
One way to fix this is to have a default no arg constructor for your
UserModel
Otherwise, if you want to have a non zero argument constructor for your ViewModel class, you may have to create a custom
ViewModelFactory
class to initialise your ViewModel instance, which will implementViewModelProvider.Factory
interface.I have not tried this yet, but here is the link to excellent sample from google for the same: github.com/googlesamples/android-architecture-components. Specifically, checkout this class GithubViewModelFactory.java for Java code and this class GithubViewModelFactory.kt for corresponding Kotlin code
The problem can be resolved by extending
UserModel
fromAndroidViewModel
which is application context aware ViewModel and requiresApplication
parameter-only constructor. (documentation)Ex- (in kotlin)
This works for version
2.0.0-alpha1
.ViewModelFactory
that will provide us a right ViewModel fromViewModelModule
ViewModelModule
is responsible for binding all over ViewModel classes intoMap<Class<? extends ViewModel>, Provider<ViewModel>> viewModels
ViewModelKey
is an annotation for using as a key in the Map and looks likeNow you are able to create ViewModel and satisfy all necessary dependencies from the graph
Instantiating ViewModel
And do not forger to add
ViewModelModule
intomodules
listIf you have parameter in constructor then :
DAGGER 2 public constructor for @inject dependency
Otherwise dagger 2 will send you error "can not instantiate viewmodel object"
I wrote a library that should make achieving this more straightforward and way cleaner, no multibindings or factory boilerplate needed, while also giving the ability to further parametrise the
ViewModel
at runtime: https://github.com/radutopor/ViewModelFactoryIn the view: