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
ViewModelStorevia thegetViewModelStore()method. - Retaining that
ViewModelStoreinstance 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 ViewModels. You don't create ViewModels 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
ActivityorFragmentstarts. Since it implementsViewModelStoreOwner, it either creates a newViewModelStoreor 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/Fragmentto get a reference to theViewModelStore.You call
viewModelProvider.get(MyViewModel.class).The
ViewModelProviderasks theViewModelStoreif it already has an instance for the key associated withMyViewModel.If yes, the existing
ViewModelinstance is returned. This is what happens during a screen rotation.
If no, theViewModelProvideruses its factory to create a newMyViewModelinstance, adds it to theViewModelStore, and then returns it.When your
Activity/Fragmentis permanently destroyed (e.g., the user presses the back button and finishes it), itsViewModelStoreOwnerimplementation callsclear()on theViewModelStore.The
ViewModelStorethen callsonCleared()on everyViewModelit 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 ViewModels from that storage, ensuring you always get the correct instance for the given owner's lifecycle.
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.