After reading this article, how can LiveData be used like this?

The main content of this paper is:

  1. Role introduction
  2. Introduction to Core Classes
  3. Basic Use
  4. Source Code Analysis

    --Horizontal and Vertical Screen Switch Recovery
     --Background Destroy Recovery
    • *

Main work of ViewModel:

It is essentially a data maintenance tool
Separating data maintenance from Activity provides a data storage environment, and its own mechanism can solve the problem of data loss (mainly horizontal and vertical screen switching and destruction in the background) caused by the impact of Activity lifecycle in development.
Usually used in conjunction with LiveData.

As a pure data maintenance tool, it can be incorporated into the MVP architecture for data preservation.
The official choice is the VM layer in the AAC architecture MVVM.

    • *

The main classes of ViewModel:

  • ViewModel (VM):
    Data storage class, the core class of the architecture.
    When used, inherit the class directly and choose to override the onCleared() method as needed.
    To save data after an Activity has been destroyed by the system, define a construction method with a parameter (SavedStateHandle) and save the data in SavedStateHandle.
    Actually accessed via SavedInstanceState
  • AndroidViewModel:
    A VM subclass that maintains a reference to the Application and is passed in when the SavedStateViewModelFactory in the schema is created.
    Similarly, when you need to receive a SavedStateHandle, you need to define a construction method with a parameter (Application, SavedStateHandle).
  • ViewModelStore:
    For VM storage, a HashMap for VM storage is maintained internally.
    Typically, instances are created directly using this class.
  • ViewModelStoreOwner:
    An interface, a class that implements the interface, indicating that it can provide a VM to the outside world.
    AppCompatActivity/Fragment of androidx implements this interface.
  • ViewModelProvider:
    Provider of the VM, get the basic entry of the VM.
    Actually relies on ViewModelStore to access the VM, Factory generates/restores the VM.
  • Factory:
    Interface, the class that implements the interface is mainly used to create VM instances.
    It is not recommended to implement this interface directly unless you understand the content of the framework and your own needs.
    In general, you can use the AndroidViewModelFactory if you do not need the SavedStateHandle mechanism.
    Otherwise, SavedStateViewModelFactory should be used or inherited.
    • *

Basic use of ViewModel:

  • General use:
// VM
class ViewModelA : ViewModel()
// AVM
class ViewModelB(app: Application) : AndroidViewModel(app)

// In Activity/Fragment.onCreate
override fun onCreate() {
  val provider = ViewModelProvider(this)
  val vmA = provider.get(
  val vmB = provider.get(
  • Accept SavedStateHandle
// VM
class ViewModelC(
        val handle: SavedStateHandle
) : ViewModel()

// AVM
class ViewModelD(
        app: Application, 
        val handle: SavedStateHandle
) : AndroidViewModel(app)
  • Sharing data across fragments

    Fragment directly uses Activity as the Key for ViewModel
val provider = ViewModelProvider(requireActivity())
val vmA = provider.get(
  • Create a globally shared VM through Application
class App : Application(), ViewModelStoreOwner {
    private lateinit var mAppViewModelStore: ViewModelStore
    private lateinit var mFactory: ViewModelProvider.Factory

    override fun onCreate() {
        mAppViewModelStore = ViewModelStore()
        mFactory = ViewModelProvider

    override fun getViewModelStore(): ViewModelStore {
        return mAppViewModelStore

    private fun getAppFactory(): ViewModelProvider.Factory {
        return mFactory

    fun getAppViewModelProvider(activity: Activity): ViewModelProvider {
        val app = checkApplication(activity) as App
        return ViewModelProvider(app, app.getAppFactory())

    fun getAppViewModelProvider(fragment: Fragment): ViewModelProvider {
        return getAppViewModelProvider(fragment.requireActivity())

    private fun checkApplication(activity: Activity): Application {
        return activity.application
                ?: throw IllegalStateException(
                      "Your activity is not yet attached to the Application instance." + 
                      "You can't request ViewModel before onCreate call.")
    • *

Key Source Analysis for ViewModel:

The following source analysis will remove unrelated code to simplify

  • ViewModelProvider implementations are relevant:

As mentioned earlier, the work of the ViewModelProvider is entirely dependent on the incoming ViewModelStore and Factory, which you can tell directly from the construction method:

private final Factory mFactory;
private final ViewModelStore mViewModelStore;

public ViewModelProvider(ViewModelStoreOwner owner) {
        owner instanceof HasDefaultViewModelProviderFactory
        ? ((HasDefaultViewModelProviderFactory) owner)
        : NewInstanceFactory.getInstance());

public ViewModelProvider(ViewModelStoreOwner owner, Factory factory) {
    this(owner.getViewModelStore(), factory);

public ViewModelProvider(ViewModelStore store, Factory factory) {
    mFactory = factory;
    mViewModelStore = store;

// Simple Reflection Create Instance Factory
public static class NewInstanceFactory implements Factory {
    public <T extends ViewModel> T create(Class<T> modelClass) {
        return modelClass.newInstance()

androidx.activity.ComponentActivity, all implement the ViewModelStoreOwner, HasDefaultViewModelProviderFactory interface.

public class AppCompatActivity extends FragmentActivity...{}
public class FragmentActivity extends ComponentActivity...{}

public class ComponentActivity extends ... implements
        SavedStateRegistryOwner ... {}

public class Fragment implements 
        SavedStateRegistryOwner ... {}

The get() method of ViewModelProvider returns a VM instance where mFactory is SavedStateViewModelFactory:

private static final String DEFAULT_KEY 
      = "androidx.lifecycle.ViewModelProvider.DefaultKey";

public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    String canonicalName = modelClass.getCanonicalName();
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);

public <T extends ViewModel> T get(String key, Class<T> modelClass) {
    ViewModel viewModel = mViewModelStore.get(key);

    // A guarantee mechanism
    if (modelClass.isInstance(viewModel)) {
        if (mFactory instanceof OnRequeryFactory) {
            ((OnRequeryFactory) mFactory).onRequery(viewModel);
        return (T) viewModel;

    // Normal and basic logic
    if (mFactory instanceof KeyedFactory) {
        viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
    } else {
        viewModel = (mFactory).create(modelClass);

    mViewModelStore.put(key, viewModel);
    return (T) viewModel;

SavedStateViewModelFactory is resolved later.

    • *
  • Screen Horizontal and Vertical Switching Recovery Mechanism for ViewModel:

Previously, the creation of a VM was achieved through the ViewModelProvider, which relies on the ViewModelStore for VM storage.
When ComponentActivity/Fragment is used as an initialization parameter for ViewModelProvider, the storage container for the actual VM is provided by the parameter.

  1. ComponentActivity implementation:

From the source code, you can see that the horizontal and vertical screen switches are recovered directly through NonConfiguration Instances.

ComponentActivity contains a NonConfigurationInstances class that holds a reference to ViewModelStore:

static final class NonConfigurationInstances {
    Object custom;
    ViewModelStore viewModelStore;

Save ViewModelStore:
Save ViewModelStore in horizontal and vertical switching with onRetainNonConfiguration Instance ()

public final Object onRetainNonConfigurationInstance() {
    Object custom = onRetainCustomNonConfigurationInstance();

    // Restore ViewModelStore from the previous NonConfiguration Instances
    ViewModelStore viewModelStore = mViewModelStore;
    if (viewModelStore == null) {
        NonConfigurationInstances nc = 
                (NonConfigurationInstances) getLastNonConfigurationInstance();

        if (nc != null) {
            viewModelStore = nc.viewModelStore;

    if (viewModelStore == null && custom == null) {
        return null;

    // Save the current ViewModelStore
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    nci.viewModelStore = viewModelStore;
    return nci;

Attempt to restore ViewModelStore through getLastNonConfiguration Instance() while in use:

public ViewModelStore getViewModelStore() {
    if (mViewModelStore == null) {
        NonConfigurationInstances nc = 
                (NonConfigurationInstances) getLastNonConfigurationInstance();

        if (nc != null) {
            // Restore ViewModelStore directly from the NonConfiguration Instances object
            mViewModelStore = nc.viewModelStore;
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
    return mViewModelStore;
  1. Fragment implementation:

To understand this part of the source code, you need to have a basic understanding of FragmentManager. Reference: Deep understanding of FragmentManager

The Fragment ViewModelStore is managed by the Fragment Manager ViewModel maintained by Fragment Manager.

  • Note that a VM is used here to maintain a ViewModelStore

public ViewModelStore getViewModelStore() {
    return mFragmentManager.getViewModelStore(this);

private FragmentManagerViewModel mNonConfig;

ViewModelStore getViewModelStore(Fragment f) {
    return mNonConfig.getViewModelStore(f);

Processing instantiation of the FragmentManagerViewModel:

void attachController(FragmentHostCallback<?> host, 
                      FragmentContainer container,
                      final Fragment parent) {
    mHost = host;
    mParent = parent;

    if (parent != null) {
        // Get from parent FM
        mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
    } else if (host instanceof ViewModelStoreOwner) {
        // Suppose the host object implements ViewModelStoreOwner
        // Use this ViewModelStoreOwner's viewModelStore to create a FragmentManagerViewModel
        ViewModelStore viewModelStore = 
                ((ViewModelStoreOwner) host).getViewModelStore();
        mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
    } else {
        // Generate a FragmentManagerViewModel that does not support automatic saving of ViewModels
        mNonConfig = new FragmentManagerViewModel(false);

However, as you can see from the source notes, the third scenario is obsolete and ideally not supported.

So basically, the first and second scenarios should occur.

The host object is actually a FragmentActivity$HostCallbacks that implements the ViewModelStoreOwner interface:

class HostCallbacks 
            extends FragmentHostCallback<FragmentActivity> 
            implements ViewModelStoreOwner ... {...}

In the second case, the attachController() incoming parameter is null, which can be interpreted as a Fragment attached directly to the FragmentActivity:

protected void onCreate(@Nullable Bundle savedInstanceState) {
    mFragments.attachHost(null /*parent*/);

public void attachHost(Fragment parent) {
    mHost.mFragmentManager.attachController(mHost, mHost, parent);

In the first case, the attachController() passed in parameter is Fragment, which is called in the performAttach() of Fragment:

void performAttach() {
    mChildFragmentManager.attachController(mHost, new FragmentContainer(), this)

Resolved the source of the FragmentManagerViewModel, and see what it does below.
As mentioned above, the FragmentManager ViewModel is a VM and can actually be associated with a recovery that may have been achieved through the Activity's ViewModelStore using the same NonConfiguration Instances mechanism.

Look at the second scenario first:

ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);

Whereas host is FragmentActivity$HostCallbacks, getViewModelStore() actually returns ViewModelStore for FragmentActivity:


public ViewModelStore getViewModelStore() {
    return FragmentActivity.this.getViewModelStore();

Internally, FragmentManagerViewModel.getInstance() actually returns a VM instance of this type through the ViewModelProvider:

FragmentManagerViewModel .java

static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
    ViewModelProvider viewModelProvider = 
                new ViewModelProvider(viewModelStore, FACTORY);
    return viewModelProvider.get(FragmentManagerViewModel.class);

Since the VM is stored in the corresponding ViewModelStore when it is created, it is stored in the ViewModelStore of the FragmentActivity.

First case:
In fact, in the FragmentManagerViewModel of the top-level FragmentManager, a child FragmentManagerViewModel repository is maintained, and then all child FragmentManagerViewModels are maintained directly through the top-level FragmentManager ViewModel.

FragmentManagerViewModel .java

private final HashMap<String, FragmentManagerViewModel> mChildNonConfigs = new HashMap<>();

FragmentManagerViewModel getChildNonConfig(@NonNull Fragment f) {
    FragmentManagerViewModel childNonConfig = mChildNonConfigs.get(f.mWho);
    if (childNonConfig == null) {
        childNonConfig = new FragmentManagerViewModel(mStateAutomaticallySaved);
        mChildNonConfigs.put(f.mWho, childNonConfig);
    return childNonConfig;

As you can see from the above source code, Fragment's horizontal and vertical switching recovery mechanism is actually:

  • Recover through the mechanism of the Activity by attaching to the Activity's ViewModelStore through a VM that holds its own ViewModelStore reference.

In fact, it is mentioned in the source code that the NonConfiguration Instances mechanism may return null when getLastNonConfiguration Instance is called. To ensure data preservation during horizontal and vertical screen switching, you can use Fragment's onSaveInstance State (true) as a container to store data.

In fact, in older versions of ViewModel, it was done through Fragment's onSaveInstanceState(true).

    • *
  • Background destruction recovery mechanism for ViewModel:

As mentioned earlier, SavedStateViewModelFactory is part of this implementation, and the VM generated by SavedStateViewModelFactory has the ability to access data through SavedStateHandle before and after background destruction.

    • *

First look at how SavedStateViewModelFactory is constructed:

public SavedStateViewModelFactory(Application application,
                                  SavedStateRegistryOwner owner,
                                  Bundle defaultArgs) {

    mSavedStateRegistry = owner.getSavedStateRegistry();
    mLifecycle = owner.getLifecycle();
    mDefaultArgs = defaultArgs;
    mApplication = application;
    mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);

The parameters that SavedStateViewModelFactory instantiates in ComponentActivity are:

mDefaultFactory = new SavedStateViewModelFactory(
                            getIntent() != null ? getIntent().getExtras() : null);

ComponentActivity implements the SavedStateRegistryOwner interface, whose implementation class can provide SavedStateRegistry instances.

    • *

SavedStateRegistry is one of the key objects in the process.
This refers to a new component provided by androidx, androidx.savedstate:'This component allows components to be added to the SaveInstanceState process as plug-ins'.

Personal understanding:
This is an encapsulation tool for the SavedState operation Bundle, but only for system implementations.
Because of the cumbersome process, the system source code also contains a series of operations such as automatic rebuilding, automatic data restore, life cycle assurance, etc.
Bundle s are also written when you implement the key SavedStateProvider interface, which is not much different from the traditional onSaveInstanceState().
Because the system implements the access operations provided by the VM, it is recommended that the VM be used directly or that the data be manipulated directly in onSaveInstanceState().

I'll write a separate article later to discuss how the system implements this component.

    • *

When ComponentActivity is instantiated, the member SavedStateRegistryController is created, and when the latter is instantiated, the member SavedStateRegistry is created:

private final SavedStateRegistryController mSavedStateRegistryController =

public static SavedStateRegistryController create(SavedStateRegistryOwner owner) {
    return new SavedStateRegistryController(owner);

private SavedStateRegistryController(SavedStateRegistryOwner owner) {
    mOwner = owner;
    mRegistry = new SavedStateRegistry();

ComponentActivity calls SavedStateRegistryController.performSave() in onSaveInstanceState(), and internally calls SavedStateRegistry.performSave():

protected void onSaveInstanceState(Bundle outState) {

public void performSave(Bundle outBundle) {

SavedStateRegistry retrieves data from the saveState() registered with its own SavedStateProvider and saves it in a Bundle:

void performSave(@NonNull Bundle outBundle) {
    Bundle components = new Bundle();
    for (Iterator<Map.Entry<String, SavedStateProvider>> it = 
                    mComponents.iteratorWithAdditions(); it.hasNext(); ) {

        Map.Entry<String, SavedStateProvider> entry1 =;
        components.putBundle(entry1.getKey(), entry1.getValue().saveState());
    outBundle.putBundle(SAVED_COMPONENTS_KEY, components);

This explains the initiation of the data save and eventually notifies SavedStateRegistry.

    • *

First look at the SavedStateProvider interface:

Registering the implementation class in SavedStateRegistry will call saveState() to get data during the SavedStateRegistry save process.
Later, when the data is recovered, the saved data will be retrieved through SavedStateRegistry.consumeRestoredStateForKey().

SavedStateProvider is registered with SavedStateRegistry through SavedStateRegistry.registerSavedStateProvider():

public void registerSavedStateProvider(String key, SavedStateProvider provider) {
    SavedStateProvider previous = mComponents.putIfAbsent(key, provider);
    if (previous != null) {
        throw new IllegalArgumentException(
                "SavedStateProvider with the given key is already registered");

This indicates that the provider storing the data is the SavedStateProvider registered with the SavedStateRegistry.

    • *

As mentioned earlier, the core of VM's access is SavedStateHandle, so there is a necessary association between SavedStateProvider and Saved StateHandle.
In fact, in the SavedStateHandle instance, an anonymous internal class instance of SavedStateProvider is maintained, while both the read and write operations of SavedStateHandle and the data read and write operations of SavedStateProvider instances are read and write to the actual data container mRegular.

First look at SavedStateHandle:

  • As mentioned earlier, the final implementation of this mechanism, which is actually the SaveInstanceState mechanism, reflects that the VM does not automatically access data.

    In fact, `VM` does need to manually put the data saved before background destruction into `SaveInstanceState', `SavedStateHandle` does, so a series of `get`/`set` operations are provided, and eventually a `Bundle'conversion of `SavedStateProvider` is required.
  • You can also see that SavedStateHandle provides access to LiveData.

    `SavedStateHandle`Support for `LiveData` comes from the internal static wrapper class`SavingStateLiveData` for `LiveData'.
    `SavingStateLiveData` wraps `setValue()` and the incoming parameters are stored in `mRegular` first.

SavedStateProvider for extracting data:

A Bundle transformation operation for SavedStateProvider data needs to be written.
Therefore, if it is not necessary to customize this component, it is recommended that you operate directly in onSaveInstanceState().

// Final data container body
// initialState is the old data from the last SavedInstanceState that was included in the construction
// The parameters passed in when SavedStateHandle.createHandle are described below
final Map<String, Object> mRegular = new HashMap<>(initialState);

// SavedStateProvider processes the data body mRegular and generates a Bundle
private final SavedStateProvider mSavedStateProvider = new SavedStateProvider() {
        public Bundle saveState() {
            Set<String> keySet = mRegular.keySet();
            ArrayList keys = new ArrayList(keySet.size());
            ArrayList value = new ArrayList(keys.size());
            for (String key : keySet) {
            Bundle res = new Bundle();
            // "parcelable" arraylists - lol
            res.putParcelableArrayList("keys", keys);
            res.putParcelableArrayList("values", value);
            return res;

At this point, SavedStateHandle and Saved StateProvider implement the association.

    • *

As mentioned earlier, SavedStateProvider is registered with SavedStateRegistry through SavedStateRegistry.registerSavedStateProvider():

This method is called through SavedStateHandleController.
Instantiation of SavedStateHandleController is done through SavedStateViewModelFactory, which eventually returns to the SavedStateViewModelFactory.

First look at the SavedStateViewModelFactory:

Returns the SavedStateHandleController instance by calling SavedStateHandleController.create().
At the same time, the VM was created with Saved StateHandleHandle instance passed in as a parameter, that is, the VM and Saved StateHandle were bound.

public <T extends ViewModel> T create(String key, Class<T> modelClass) {

    // Determine if it is an AVM
    boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
    Constructor<T> constructor;
    if (isAndroidViewModel) {
        constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
    } else {
        constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);

    // If SavedStateHandle is not required, create a normal VM/AVM directly
    if (constructor == null) {
        return mFactory.create(modelClass);

    // Created SavedStateHandleController 
    SavedStateHandleController controller = SavedStateHandleController.create(
                                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);

    // VM holds SavedStateHandle objects maintained within SavedStateHandleController when created
    try {
        T viewmodel;
        if (isAndroidViewModel) {
            viewmodel = constructor.newInstance(mApplication, controller.getHandle());
        } else {
            viewmodel = constructor.newInstance(controller.getHandle());
        viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
        return viewmodel;

Look again at SavedStateHandleController.create():

When SavedStateHandle is instantiated, the last saved data is passed in through consumeRestoredStateForKey(), and the SavedStateHandle data is now recovered.
After the SavedStateHandleController is created, SavedStateProvider maintained by the SavedStateHandle is registered with the SavedStateRegistry within the method via the attachToLifecycle() method.

As mentioned earlier, SavedStateViewModelFactory is one of the framework frameworks, and it is through this process that VM is ultimately allowed to incorporate data access into the SaveInstanceState process.

static SavedStateHandleController create(SavedStateRegistry registry, 
                      Lifecycle lifecycle, String key, Bundle defaultArgs) {

    // Get previous status through consumeRestoredStateForKey
    Bundle restoredState = registry.consumeRestoredStateForKey(key);
    // Create a Handle
    SavedStateHandle handle = 
                SavedStateHandle.createHandle(restoredState, defaultArgs);

    // Generate SavedStateHandleController instance
    SavedStateHandleController controller = 
                new SavedStateHandleController(key, handle);

    // There are bindings
    controller.attachToLifecycle(registry, lifecycle);
    tryToAddRecreator(registry, lifecycle);
    return controller;

void attachToLifecycle(SavedStateRegistry registry, Lifecycle lifecycle) {
    registry.registerSavedStateProvider(mKey, mHandle.savedStateProvider());

At this point, SavedStateProvider and Saved StateRegistry implement associations.

    • *

This is an overview of the entire save process, and the restore process is not far apart. Instead, call SavedStateRegistryController.performRestore() in onCreate() and eventually notify SavedStateRegistry to restore the set data in Bundle.

    • *

Ignore SavedStateHandleController's VM assurance mechanism (including Recreator), and conclude:

  • Simplify the appellations to reduce reading:

    VM Group:
    `ViewModel` = `VM`
    `SavedStateViewModelFactory` = `Factory`
    Registry Group:
    `SavedStateRegistryController` = `RegistryController`
    `SavedStateRegistry` = `Registry`
    Handle Group:
    `SavedStateHandleController` = `HandleController`
    `SavedStateHandle` = `Handle`
    Provider Group:
    `SavedStateProvider` = `Provider`
  • Initialization phase:

     `RegistryController`Created an internal`Registry`instance
     `ComponentActivity`Created`Factory` and passed in`RegistryController`Maintained`Registry`
  • Recovery phase

    `ComponentActivity`Invoke`performRestore` of `RegistryController` in `onCreate`
    In `performRestore` of `RegistryController`, call `performRestore'of `Registry`
    `Registry`in`performRestore`, take data from `savedInstanceState (Bundle)` and store it in `mRestoredState`
    ***Here`Registry`Data restored***
  • VM generation phase:

    `VM` needs to be created through `Factory', the creation process:
    --Create an instance of `HandleController'corresponding to `VM', and create the process:
    ------------ `ConsueRestoredStateForKey` of `Registry` to fetch data to generate `Handle`
    ------ `Handle`Maintain an internal `Provider` instance, shared data container `mRegular`
    ------ `HandleController`injected`Handle`
    ------ `Provider`Bind to `Registry`
    ------ *** Implementation of (`RegistryController`-`Registry`-`Provider`-`Handle`) binding here***
    --`VM`injected by`Factory``Handle`
    --***The (`RegistryController`-`Registry`-`Provider`-`Handle-VM`) binding is implemented here***
    --***`VM`Data eventually recovered through`Registry`***
  • Write Data Phase

    `VM`Read-Write data ends up in`mRegular`of`Handle`
    ***`VM`Data ultimately saved through`Registry`***
  • Save Phase

    In `performSave'of `RegistryController`, call `performSave' of `Registry`
    `Registry`in`performSave`, package all registered`Provider`data into a`Bundle` and save it in`onSaveInstanceState`in`Bundle`
    ***Saved data here`Registry`***

Author: 708 question mark

Tags: Android Java Fragment Google

Posted on Tue, 10 Mar 2020 23:46:41 -0400 by Cognito