Possible to access AndroidViewModel of Activity via Fragment?
So I checked the docs and as I understood right I should now use
ViewModelProvider.AndroidViewModelFactory.getInstance( this.getApplication()).create(CanteensViewModel.class);
Please share a link to this "docs" you mentioned, because this is NOT the first time I see this code, and yet it was equally wrong in both cases.
The code you actually should be using is
new ViewModelProvider(this).get(CanteensViewModel.class);
Is there a way I can access the Activity's ViewModel from inside the fragments? Or would it be better to recreate the ViewModel in each fragment by
new ViewModelProvider(requireActivity()).get(CanteensViewModel.class);
Consider also receiving a SavedStateHandle
as an argument in your AndroidViewModel
, and not only Application
.
If you ask me, apparently the removal of ViewModelProviders.of()
was an API mistake, but this is what we have now.
EDIT: With the help of the provided stack trace, I can finally somewhat figure out what's going on.
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219)
We are using NewInstanceFactory
as the default. What does default NewInstanceFactory
do? It just calls no-arg constructor if available.
Wait, what? Isn't it supposed to fill in the Application
for an AndroidViewModel
?
Theoretically yes, as long as you got the original default ViewModelProvider.Factory
, but this is not the one!
Why is it not the one that can fill in AndroidViewModel?
See this commit
Add default ViewModel Factory interface Use a marker interface to allow instances of ViewModelStoreOwner, such as ComponentActivity and Fragment, to provide a default ViewModelProvider.Factory that can be used with a new, concise ViewModelProvider constructor. This updates ComponentActivity and Fragment to use that new API to provide an AndroidViewModelFactory by default. It updates the 'by viewModels' Kotlin extensions to use this default Factory if one isn't explicitly provided.
Also
ComponentActivity: + @NonNull + @Override + public ViewModelProvider.Factory getDefaultViewModelProviderFactory() { + if (getApplication() == null) { + throw new IllegalStateException("Your activity is not yet attached to the " + + "Application instance. You can't request ViewModel before onCreate call."); + } + return ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()); + } +
And most importantly
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) { this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory() : NewInstanceFactory.getInstance()); }
This means that you get the default view model provider factory that can properly set up AndroidViewModel if the ViewModelStoreOwner implements HasDefaultViewModelProviderFactory
.
Theoretically, ComponentActivity
is indeed a HasDefaultViewModelProviderFactory
; and AppCompatActivity
extends from ComponentActivity
.
In your case however, that doesn't seem to be the case. For some reason, your AppCompatActivity
is not HasDefaultViewModelProviderFactory
.
I think the solution to your problem is to update Lifecycle to 2.2.0, and ALSO update implementation 'androidx.core:core-ktx
to at least 1.2.0. (specifically at least AndroidX-Activity 1.1.0, and AndroidX-Fragment 1.2.0).