Android MVVM learning - the relationship between ViewModel, ViewModelProvider and ComponentActivity

Table of contents

1. The birth of ViewModel

2. The end of ViewModel

3. Summary:


We use the life cycle of ViewModel as the main line to explain the relationship between ViewModel, ViewModelProvider and ComponentActivity.

1. The birth of ViewModel

Create ViewModel by calling the get method of ViewModelProvider.

mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
//ViewModelProvider.class
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
    this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
            ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
            : NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
    mFactory = factory;
    mViewModelStore = store;
}
public ViewModelStore getViewModelStore() {
    ...
    ensureViewModelStore();
    return mViewModelStore;
}
void ensureViewModelStore() {
    if (mViewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            // Restore the ViewModelStore from NonConfigurationInstances
            mViewModelStore = nc.viewModelStore;
        }
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
}

Get the owner's ViewModelStore (AppCompatActivity compatible -> FragmentActivity -> ComponentActivity component ComponentActivty implements the ViewModelStoreOwner and LifecycleOwner interfaces)

There is a HashMap inside ViewModelStore to store ViewModel

So mViewModelStore in ViewModelStore is Activity, ViewModelProvider holds a reference to mViewModelStore, and ViewModelProvider internally holds a reference to mViewModelStore

//ViewModelProvider.class
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    ...
    return get(DEFAULT_KEY + ":" + modelClass.getCanonicalName(), modelClass);
}

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

    if (modelClass.isInstance(viewModel)) {
        if (mFactory instanceof OnRequeryFactory) {
            ((OnRequeryFactory) mFactory).onRequery(viewModel);
        }
        return (T) viewModel;
    } else {
        //noinspection StatementWithEmptyBody
        if (viewModel != null) {
            // TODO: log a warning.
        }
    }
    if (mFactory instanceof KeyedFactory) {
        viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
    } else {
        viewModel = mFactory.create(modelClass);
    }
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}

public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
    return modelClass.newInstance();
    ...
}

The get method will create a ViewModel object, using the Factory factory to create it, and the factory creates the ViewModel through reflection.

And because we use ViewModelProvider (ViewModelStoreOwner) to create ViewModelProvider, the ViewModelProvider.Factory used here is actually ComponentActivity, because ComponentActivity implements the HasDefaultViewModelProviderFactory interface.

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
...
        HasDefaultViewModelProviderFactory{
    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
        ...
        mDefaultFactory = new SavedStateViewModelFactory(
                getApplication(),
                this,
                getIntent() != null ? getIntent().getExtras() : null);
    
        return mDefaultFactory;
    }                                         
}

So far, the ViewModel we created is actually saved in the HashMap of mViewModelStore, and mViewModelStore is a member variable belonging to Activity.

2. The end of ViewModel

Start: The creation of ViewModel has been said a lot above, the beginning of life is from the creation of ViewModel

End: The end of life is not controlled by ourselves, because our ViewModel is stored in the ViewModelStore of Activity, so the end of life is also handled by Activity.

public ComponentActivity() {
    Lifecycle lifecycle = getLifecycle();
    ...
    getLifecycle().addObserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                ...
                getViewModelStore().clear();
            }
        }
    });
    ...
}

When creating ComponentActivity, we registered the Lifecycle listener of Activity. When Activity.onDestory, all ViewModels will be cleared automatically, and an onCleared callback will be given to ViewModel, telling it that no one has referenced it. and to

The mBagOfTags in the ViewModel call the close method one by one

//ViewModel.class
protected void onCleared() {
}

@MainThread
final void clear() {
    mCleared = true;
    if (mBagOfTags != null) {
        synchronized (mBagOfTags) {
            for (Object value : mBagOfTags.values()) {
                // see comment for the similar call in setTagIfAbsent
                closeWithRuntimeException(value);
            }
        }
    }
    onCleared();
}

To sum up, ViewModel has a life cycle, and the end of life is controlled by Activity

3. Summary:

1. ViewModelProvider is actually just an intermediary:

The creation of ViewModel, the factory ViewModelProvider.Factory is actually held by ComponentActivity.

For the storage of ViewModel, ViewModelStore is responsible and held by ComponentActivity.

The destruction of ViewModel is still in charge of ComponentActivity.

2. ViewModel is the core VM in MVVM, and ComponentActivity is responsible for the life cycle and storage.

3. ComponentActivity is the sole steward of ViewModel.

4. The view layer in MVVM is referenced by the viewmodel layer.

Guess you like

Origin blog.csdn.net/mldxs/article/details/127172019