Let's dive into the relationship between ViewModel
, ViewModelProvider
, ViewModelStoreOwner
, and ViewModelStore
by examining their roles and interactions within the AOSP codebase.
Think of these four components working together as a system for managing and persisting UI data across configuration changes like screen rotations.
The Core Components Explained
1. ViewModel
๐ง
This is the class you'll interact with most directly. Its primary job is to hold and manage UI-related data. The key feature of a ViewModel
is that it survives configuration changes that would normally destroy and recreate an Activity
or Fragment
.
When a ViewModel
is no longer needed (because its associated UI component is permanently destroyed), its onCleared()
method is called to free up any resources.
2. ViewModelStore
๐๏ธ
This is a simple container class. As its name suggests, its only job is to store ViewModel
instances. Under the hood, it uses a HashMap<String, ViewModel>
to map a key (usually derived from the ViewModel
's class name) to the ViewModel
instance itself.
From the AOSP source, we can see its core implementation:
// A simplified view from the source
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
final ViewModel get(String key) {
return mMap.get(key);
}
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
3. ViewModelStoreOwner
๐งโ๐ผ
This is an interface that provides a ViewModelStore
to other objects. Any class that implements ViewModelStoreOwner
is responsible for two things:
- Providing a
ViewModelStore
via thegetViewModelStore()
method. - Retaining that
ViewModelStore
instance across configuration changes and calling itsclear()
method when the scope is permanently destroyed.
The most common implementers of this interface are ComponentActivity
and Fragment
. They handle the logic of saving and restoring the ViewModelStore
for you.
// The simple interface definition
public interface ViewModelStoreOwner {
@NonNull
ViewModelStore getViewModelStore();
}
4. ViewModelProvider
๐ญ
This is the factory and retriever for ViewModel
s. You don't create ViewModel
s directly; you ask a ViewModelProvider
for one. It's responsible for either creating a new ViewModel
instance or, more importantly, retrieving an existing one from the ViewModelStore
.
When you create a ViewModelProvider
, you give it a ViewModelStoreOwner
(like an Activity
or Fragment
). The provider then uses the owner to get access to the ViewModelStore
.
// One of the main constructors
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
// The core 'get' method logic
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key); // Check the store first
if (modelClass.isInstance(viewModel)) {
// ViewModel already exists, return it
return (T) viewModel;
}
// ViewModel doesn't exist, create it using the factory
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel); // Put the new instance in the store
return (T) viewModel;
}
The Relationship: How They Work Together
Here's the step-by-step flow that connects all four components:
Your
Activity
orFragment
starts. Since it implementsViewModelStoreOwner
, it either creates a newViewModelStore
or retrieves a previously saved one (if a configuration change just happened).To get your
ViewModel
, you instantiate aViewModelProvider
, passing yourActivity
/Fragment
(this
) as theViewModelStoreOwner
.The
ViewModelProvider
's constructor callsgetViewModelStore()
on yourActivity
/Fragment
to get a reference to theViewModelStore
.You call
viewModelProvider.get(MyViewModel.class)
.The
ViewModelProvider
asks theViewModelStore
if it already has an instance for the key associated withMyViewModel
.If yes, the existing
ViewModel
instance is returned. This is what happens during a screen rotation.
If no, theViewModelProvider
uses its factory to create a newMyViewModel
instance, adds it to theViewModelStore
, and then returns it.When your
Activity
/Fragment
is permanently destroyed (e.g., the user presses the back button and finishes it), itsViewModelStoreOwner
implementation callsclear()
on theViewModelStore
.The
ViewModelStore
then callsonCleared()
on everyViewModel
it holds, allowing them to clean up their resources.
In essence, the ViewModelStoreOwner
(the UI controller) owns the ViewModelStore
(the storage). The ViewModelProvider
(the factory) acts as the middleman to create or retrieve ViewModel
s from that storage, ensuring you always get the correct instance for the given owner's lifecycle.
Top comments (0)