Offer to come, dig friends take it! I am participating in the 2022 Spring Recruit Punch card activity. Click here for details.

Introduction to the

The ViewModel class is designed to store and manage interface-related data in a life-cycle oriented manner. The ViewModel class allows data to persist after configuration changes such as screen rotation.

The ViewModel is an abstract class, and of interest internally is the onCleared() method, where we can do things like release resources.

The ViewModelStore is a very important member. It is mainly used to store ViewModel objects to ensure that the Activity does not lose data in the ViewModel after the screen rotates. There is an internal Map to store all viewModels.

ViewModelProvider. Factory at first glance, you will know is a Factory class, actually it is ViewModelProvider internal interfaces, there is only one create (clazz) method, this method is mainly used to create the ViewModel object, The ones we use are NewInstannceFactory and AndroidViewModelFactory.

The ViewModelProvider is responsible for transferring the viewModel generated by the Factory to the store. If the store already has a value, it returns the existing object directly.

ViewModelStore

Function has been mentioned above, directly look at the source ~

Public class ViewModelStore {// Hold a set of ViewModel objects. Key is the canonicalName of the ViewModel class. 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() { return new HashSet<>(mMap.keySet()); } /** * Clears internal storage and notifies ViewModels that they are no longer used. */ public final void clear() { for  (ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); }}Copy the code

ViewModelStore source code is very simple, similar to a data store class, a ViewModel object will only store one copy.

ViewModelProvider.Factory

Factory interface has only one method, let’s look at the implementation principle together with the NewInstanceFactory source code.

public interface Factory {
    /**
     * Creates a new instance of the given `Class`.
     *
     * @param modelClass a `Class` whose instance is requested
     * @return a newly created ViewModel
     */
    public fun <T : ViewModel> create(modelClass: Class<T>): T
}

public open class NewInstanceFactory : Factory {
    @Suppress("DocumentExceptions")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return try {
            modelClass.newInstance()
        } catch (e: InstantiationException) {
            throw RuntimeException("Cannot create an instance of $modelClass", e)
        } catch (e: IllegalAccessException) {
            throw RuntimeException("Cannot create an instance of $modelClass", e)
        }
    }
}
Copy the code

The NewInstanceFactory is the official default implementation, and the create() method is simple enough to instantiate an object based on Class.

Now that we know that the Factory can instantiate a ViewModel object and store it in the ViewModelStore, let’s finally look at how the ViewModelProvider combines the two.

ViewModelProvider

To obtain a ViewModel object, use the ViewModelProvider.

val viewModel = ViewModelProvider(
            viewModelStore,
            ViewModelProvider.NewInstanceFactory.instance
        ).get(Vm::class.java)
Copy the code
  • createViewModelProviderThe object takes two arguments, both of which we parsed above, hereviewModelStoreIs through theActivityIn thegetViewModelStore()Acquired, oneActivityMaintained aViewModelStoreObject, and this object does not change after the screen rotation reconstruction, you can seeNonConfigurationInstancesThe principle of.
  • throughViewModelProvider.get(Clazz)getViewModelExample, let’s focus on this method.
@MainThread public open operator fun <T : ViewModel> get(modelClass: Class<T>): T { val canonicalName = modelClass.canonicalName ? : Throw IllegalArgumentException("Local and anonymous classes can not be ViewModels") // Return get("$DEFAULT_KEY:$canonicalName", modelClass)} @mainThread public open operator fun <T: ViewModel> get(key: String, modelClass: Class<T>): Var ViewModel = store[key] if (modelclass.isinstance (ViewModel)) {(factory) as? OnRequeryFactory)? .onRequery(viewModel) return viewModel as T } else { @Suppress("ControlFlowWithEmptyBody") if (viewModel ! = null) { // TODO: ViewModel = if (Factory is KeyedFactory) {Factory. Create (key, ModelClass)} else {factory. Create (modelClass)} // 4, store. Put (key, viewModel) return viewModel}Copy the code

The viewModelProvider.get () method is very logical, and I have explained it in four steps

The document

The official documentation

The ViewModel version