First of all, how is the ViewModel instantiated
protected open fun
getFragmentScopeViewModel(modelClass: Class<T>): T {
if(! ::fragmentProvider.isInitialized) { fragmentProvider = ViewModelProvider(this)}return fragmentProvider.get(modelClass)
}
protected open fun
getActivityScopeViewModel(modelClass: Class<T>): T {
if(! ::activityProvider.isInitialized) { activityProvider = ViewModelProvider(requireActivity()) }return activityProvider.get(modelClass)
}
Copy the code
ViewModelProvider: ViewModelProvider: ViewModelProvider: ViewModelProvider: ViewModelProvider: ViewModelProvider: ViewModelProvider: ViewModelProvider: ViewModelProvider: ViewModelProvider: ViewModelProvider: ViewModelProvider
How do I know? Look at the official answer. ViewModel: designed to store and manage data related to an interface in a life-cycle oriented manner. The ViewModel class lets the data persist after configuration changes such as screen rotation: ViewModelProvider: the ViewModel helper class that prepares the data for the interface. ViewModel objects are automatically retained during configuration changes so that the data they store is immediately available for use by the next activity or Fragment instance
Boy, it’s this pair, in life cycle fashion. What’s the difference
Activty vs. ViewModel lifecycle
Fight until Finish
Lifecycle is passed to the ViewModelProvider when the ViewModel is acquired. The ViewModel will remain in memory until Lifecycle is gone permanently: for an activity, when the activity completes; For fragments, this is when the fragment is separating
Okay, so how does the ViewModelProvider implement the construction
ViewModelProvider()
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
// Call another constructor secretly
// 1. Create a ViewModelStore to store viewModels. 2. Create a Factory to instantiate the new ViewModel
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
Copy the code
ViewModelStore
This interface is used for activities, fragments, etc., to retrieve the ViewModelStore related to the current life cycleTake a look atComponentActivity.getViewModelStore()
:
public ViewModelStore getViewModelStore(a) {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
// fork is a singleton that implements ViewModelStore
ensureViewModelStore();
// Returns the ViewModelStore associated with this Activity
returnmViewModelStore; } ` ` `void ensureViewModelStore(a) {
if (mViewModelStore == null) {
/ / retrieve the previous by onRetainNonConfigurationInstance () returns the cache configuration after configuration changes
NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
// If the cache configuration is not empty, take the viewModelStore of the cache configuration
if(nc ! =null) {
mViewModelStore = nc.viewModelStore;
}
// If not, create an example
if (mViewModelStore == null) {
mViewModelStore = newViewModelStore(); }}}Copy the code
The ViewModelStore is used to store viewModels in a HashMap.
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);
}
Set<String> keys(a) {
return new HashSet<>(mMap.keySet());
}
public final void clear(a) {
for(ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); }}Copy the code
ViewModelProviderFactory
The back of the same Activity, fragments and also realizes the HasDefaultViewModelProviderFactory interface, realize oneself create ViewModel ViewModelProviderFactory, see figureTake a look atComponentActivity.getViewModelStore()
:
public ViewModelProvider.Factory getDefaultViewModelProviderFactory(a) {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
// It's as simple as that, direct instantiation
if (mDefaultFactory == null) {
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this, getIntent() ! =null ? getIntent().getExtras() : null);
}
return mDefaultFactory;
}
Copy the code
A little things, like this instance SavedStateViewModelFactory, see how specific the get ()
// Step 1: get
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
// If the class is local or anonymous, it will crash
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
// Hey, keep getting
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
// Step 2: get
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
// Check whether there is a cache
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
}
// Then, if null, instantiate the ViewModel through the concrete factory class
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
} else {
viewModel = mFactory.create(modelClass);
}
// Put it in cache
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
// Instantiate the ViewModel
public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
Constructor<T> constructor;
// Use reflection to find the current ViewModel constructor
if(isAndroidViewModel && mApplication ! =null) {
constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
} else {
constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
}
if (constructor == null) {
return mFactory.create(modelClass);
}
SavedStateHandleController controller = SavedStateHandleController.create(
mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
// call the constructor to instantiate
try {
T viewmodel;
if(isAndroidViewModel && mApplication ! =null) {
viewmodel = constructor.newInstance(mApplication, controller.getHandle());
} else {
viewmodel = constructor.newInstance(controller.getHandle());
}
viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
return viewmodel;
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to access " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("An exception happened in constructor of "+ modelClass, e.getCause()); }}Copy the code
The architectural role of the ViewModel
Salute to the official, do not understand the gold content of this map, do not understand MMVM