Blog Infos
Author
Published
Topics
, , , ,
Published

One of the most common challenges Android developers face is managing data across configuration changes, such as screen rotations. Traditionally, saving and restoring data required handling onSaveInstanceState() or using retained fragments. The ViewModel architecture component simplifies this process by surviving configuration changes and retaining UI-related data. But how does the ViewModel achieve this persistence internally? Let’s dive deep into the mechanics and internal implementation of the ViewModel system.

What is a ViewModel?

ViewModel is a lifecycle-aware component designed to hold and manage UI-related data in a way that survives configuration changes. Unlike an Activity or Fragment, which can be recreated during such changes, a ViewModel is retained as long as its owning Lifecycle (e.g., an Activity or Fragment) is alive.

How Does ViewModel Survive Configuration Changes?

The key to the ViewModel‘s persistence lies in its relationship with the ViewModelStore, which is managed by a ViewModelStoreOwner (e.g., ActivityFragment). Here’s an in-depth look at how this works:

1. The Lifecycle of an Activity

When an Activity undergoes a configuration change, the Android system destroys the old instance and creates a new one. To retain certain objects (like the ViewModel) across this recreation, the Android system provides the NonConfigurationInstance mechanism.

  • The ComponentActivity class (a part of androidx.activity) uses this mechanism to retain the ViewModelStore, which is a container for ViewModel instances.
  • Upon recreation, the new Activity instance retrieves the same ViewModelStore, allowing it to access existing ViewModel instances.
2. The Role of ViewModelStore

The ViewModelStore is a simple map-like structure that holds ViewModel instances, keyed by their names. Here’s how it’s defined:

public class ViewModelStore {
    private final HashMap<String, ViewModel> mMap = new HashMap<>();
    
    void put(String key, ViewModel viewModel) {
        mMap.put(key, viewModel);
    }
   ViewModel get(String key) {
        return mMap.get(key);
    }
    void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

. . .

 

3. Integration in ComponentActivity

The ComponentActivity (a base class for activities in Jetpack) initializes and retains the ViewModelStore. Here’s how it works internally:

a. Initialization

When an Activity is created, its ViewModelStore is initialized:

private ViewModelStore mViewModelStore;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (mViewModelStore == null) {
        mViewModelStore = new ViewModelStore();
    }
}
b. Retention Across Config Changes

When the Activity is about to be destroyed due to a configuration change, the ViewModelStore is retained through onRetainNonConfigurationInstance():

@Override
protected Object onRetainNonConfigurationInstance() {
    return mViewModelStore;
}

During recreation, the retained ViewModelStore is restored:

@Override
public Object getLastNonConfigurationInstance() {
    return mViewModelStore;
}

This mechanism ensures the ViewModelStore (and thus the ViewModel instances) persist across configuration changes.

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

No results found.

Jobs

No results found.

4. ViewModel Creation and Retrieval

The ViewModelProvider is responsible for managing the lifecycle of ViewModel instances. When you request a ViewModel, the ViewModelProvider checks if an instance already exists in the ViewModelStore. If it does, the existing instance is returned; otherwise, a new instance is created.

a. Getting a ViewModel

 

public <T extends ViewModel> T get(Class<T> modelClass) {
    String key = modelClass.getCanonicalName();
    ViewModel viewModel = mViewModelStore.get(key);
    if (viewModel == null) {
        viewModel = mFactory.create(modelClass);
        mViewModelStore.put(key, viewModel);
    }
    return (T) viewModel;
}

 

  • The ViewModelProvider uses the class name as the key to store and retrieve ViewModel instances.
  • If no instance exists for the given class, a new one is created using a ViewModelProvider.Factory.
b. Lifecycle Awareness

The ViewModel is cleared automatically when the Activity or Fragment is truly destroyed (e.g., back navigation). The clear() method in ViewModelStore ensures that resources are released:

void clear() {
    for (ViewModel vm : mMap.values()) {
        vm.clear();
    }
    mMap.clear();
}
Internal Flow of ViewModel Persistence

Activity Creation:

  • The ViewModelStore is initialized.

Requesting a ViewModel:

  • The ViewModelProvider checks the ViewModelStore for an existing instance.
  • If none exists, a new instance is created and stored.

Configuration Change:

  • The ViewModelStore is retained via onRetainNonConfigurationInstance().
  • The new Activity retrieves the retained ViewModelStore.

Activity Destruction:

  • If the Activity is truly destroyed (not a config change), the ViewModelStore and its contents are cleared.
Why Use ViewModel?
Advantages
  1. Persistence Across Config Changes: No need to manually save and restore data.
  2. Lifecycle Awareness: Automatically cleared when the Activity or Fragment is destroyed.
  3. Separation of Concerns: Keeps UI logic out of Activity and Fragment classes.
Limitation
  • The ViewModel is not a replacement for onSaveInstanceState() for persisting small amounts of data across process death.
  • Data in a ViewModel is not saved when the app is completely killed by the system.
Conclusion

The ViewModel architecture component is a powerful tool for managing UI-related data in Android. Its ability to survive configuration changes is made possible by the ViewModelStore, which is retained across Activity recreations using the onRetainNonConfigurationInstance() mechanism. By understanding the internal workings of the ViewModel, developers can better appreciate its role in simplifying state management and ensuring a seamless user experience.

Embrace the ViewModel in your projects to reduce boilerplate code and achieve cleaner architecture!

This article is previously published on proandroiddev.com.

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
Using annotations in Kotlin has some nuances that are useful to know
READ MORE
blog
One of the latest trends in UI design is blurring the background content behind the foreground elements. This creates a sense of depth, transparency, and focus,…
READ MORE
blog
Now that Android Studio Iguana is out and stable, I wanted to write about…
READ MORE
blog
The suspension capability is the most essential feature upon which all other Kotlin Coroutines…
READ MORE
Menu