Mobile Development 22 min read

Understanding Android ViewModel: State Preservation, onRetainNonConfigurationInstance, and Implementation Details

This article explains how Android ViewModel preserves UI state across configuration changes, the role of SavedStateHandle and onRetainNonConfigurationInstance, the internal mechanisms involving ComponentActivity and ViewModelStore, and provides practical guidance on using factories, CreationExtras, and Hilt for custom ViewModel implementations.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Understanding Android ViewModel: State Preservation, onRetainNonConfigurationInstance, and Implementation Details

1. ViewModel Origin – Starting from State Saving

1.1 SavedState is not a ViewModel feature

In the "State Saving and SavedState" chapter we introduced the relationship between ViewModel and SavedState . The SavedStateHandle solves two problems for ViewModel : accessing component arguments and preserving state.

Looking at the source, SavedStateHandle is passed to the ViewModel constructor, which means a default ViewModel cannot access component arguments or save state.

The significance of ViewModel for state saving is that it can survive the recreation of an Activity caused by configuration changes.

1.2 The rarely‑used onRetainNonConfigurationInstance()

Android’s Activity class contains an almost unused API onRetainNonConfigurationInstance() . It is called only when a configuration change forces the activity to be destroyed.

Compared with onSaveInstanceState(Bundle) , the former supports any type, has no size limit, and stores the object directly in memory, while the latter is limited to primitive, Parcelable, or Serializable types and is limited to 1 MB because of Binder constraints.

onSaveInstanceState(Bundle)
onRetainNonConfigurationInstance()

Call timing

Before/after

onStop()

When configuration changes

Supported types

Primitive, Parcelable, Serializable

Any type

Size limit

≈1 MB (Binder limit)

No limit

Implementation

Deserialize via Binder then store in memory

Store directly in memory

Because its call timing is very limited, most developers prefer onSaveInstanceState(Bundle) for all state‑saving needs, which makes onRetainNonConfigurationInstance() rarely used.

1.3 Should we discard or extend it?

If you understand Binder’s serialization overhead, you will see that large objects such as loaded bitmaps are inefficient to store via onSaveInstanceState . onRetainNonConfigurationInstance() therefore provides a space for caching large objects across configuration changes.

Google’s ViewModel is actually built on top of this API, offering the same “survive configuration change” capability without the boiler‑plate.

1.4 How ViewModel crosses the configuration‑change gap

ComponentActivity’s source shows a final method onRetainNonConfigurationInstance() that returns a NonConfigurationInstances object containing a ViewModelStore . The store holds all ViewModel instances.

When the activity is recreated, the stored ViewModelStore is retrieved, giving back the same ViewModel objects.

Thus the secret of ViewModel’s persistence is the ViewModelStore saved in the non‑configuration instance.

2. What is ViewModel?

2.1 Definition

ViewModel is a container for UI‑level state and business logic. It caches state so that it survives configuration changes such as screen rotation, allowing the UI to reuse data without re‑fetching.

2.2 Simple usage

After adding a ViewModel, member variables that previously lived in an Activity are moved into the ViewModel, reducing UI‑logic coupling and making the UI easier to test and migrate.

State container

Avoid loss on configuration updates

2.3 Using SavedState

The previous chapter covers detailed usage of SavedState; this article does not repeat it.

3. ViewModel Analysis

3.1 Core components

3.1.1 ViewModel

The core ViewModel class only holds a tag map and a closeable set, which are cleared when the ViewModel is destroyed.

It is destroyed only when the component is killed for reasons other than a configuration change.

3.1.2 ViewModelStore & ViewModelStoreOwner

ViewModelStore is a map‑like container that stores ViewModel instances by key. ViewModelStoreOwner is an interface that provides access to a ViewModelStore , similar to LifecycleOwner .

The store must survive configuration changes; if its owner no longer needs it, clear() should be called.

3.1.3 ViewModelProvider & Factory

ViewModelProvider creates ViewModel instances using a Factory. Its get() method returns a cached instance or creates a new one via the factory.

3.1.4 Factory and CreationExtras

Older factories required a concrete constructor for each ViewModel, leading to many factory classes. The new CreationExtras mechanism works like an Intent‑style key‑value bundle, allowing a stateless factory to obtain any required parameters.

Pre‑defined keys include:

CreationExtras.Key

Descriptions

ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY

Distinguishes multiple VM instances

ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY

Provides the Application context

SavedStateHandleSupport.SAVED_STATE_REGISTRY_OWNER_KEY

Owner needed to create a SavedStateHandle

SavedStateHandleSupport.VIEW_MODEL_STORE_OWNER_KEY

Owner needed to create a SavedStateHandle

SavedStateHandleSupport.DEFAULT_ARGS_KEY

Bundle used to create a SavedStateHandle

3.1.5 Small summary

The diagram below shows the relationship among all components.

3.2 ViewModel recap

3.2.1 Usage flow

When ComponentActivity reaches onCreate() , a ViewModelProvider is used to obtain a ViewModel via the default factory defaultViewModelProviderFactory , which is actually a SavedStateViewModelFactory .

3.2.2 ViewModel by‑delegate

Most developers now create ViewModels with the Kotlin by viewModels delegate, which internally uses the default factory and default CreationExtras unless overridden.

4. ViewModel in Real Projects

4.1 ViewModel with empty constructor

Simply use the delegate; no extra code is needed.

4.2 ViewModel that needs SavedStateHandle

ComponentActivity and Fragment already provide a SavedStateHandle, so the delegate works out‑of‑the‑box.

4.3 ViewModel that requires additional parameters

4.3.1 Custom factory + custom CreationExtras

Define a custom key, wrap the original CreationExtras with MutableCreationExtras , and retrieve the custom parameter inside the factory.

4.3.2 Using Hilt for dependency injection

Hilt can generate the factory and provide parameters automatically, removing the need for manual factory implementations.

Reference: Using Hilt for dependency injection

Reference: Using Hilt with other Jetpack libraries

5. Summary

ViewModel is the cornerstone of Android’s MVVM era. It acts as a state container that survives configuration changes, but many developers only use it superficially. Understanding the underlying mechanisms— onRetainNonConfigurationInstance , ViewModelStore , factories, and CreationExtras—enables more robust and flexible implementations.

The article covered the core concepts, component relationships, and several practical customization patterns, leaving room for deeper exploration.

ViewModelAndroidlifecycleJetpackSavedStateHandleState Preservation
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.