ViewModel source code parsing

Source code version:

  • The ViewModel: 2.4.0
  • Android: 31
  • Androidx. Activity: the activity: 1.4.0
  • Androidx. Fragments: fragments: 1.4.0

Will use: Lifecycle

Navigation:

  • Jetpack-lifecycle source code parsing
  • Jetpack-livedata source code parsing
  • Jetpack-viewmodel source code
  • See more articles here: home page

use

Declare the ViewModel

class MyViewModel : ViewModel() {

    override fun onCleared(a) {
        super.onCleared()
    }
}
Copy the code

Access to the ViewModel

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?). {
        / / get the ViewModel
        val model = ViewModelProvider(this).get(MyViewModel::class.java)
        // observe
        model.getUsers().observe(this, Observer<List<User>>{ users ->
            // update UI}}})Copy the code

ViewModel lifecycle

The source code

Declare the ViewModel

The ViewModel class

public abstract class ViewModel {
    // Tag collection
    @Nullable
    private final Map<String, Object> mBagOfTags = new HashMap<>();
    // Whether the flag is cleared
    private volatile boolean mCleared = false;

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

    // Add data key and value. If the value of key already exists, return the existing value, otherwise add a new value.
    // If the ViewModel is cleared, the value returned is Closeable and is released by calling close. That is, the ViewModel has been cleared and a new one is added.
    @SuppressWarnings("unchecked")
    <T> T setTagIfAbsent(String key, T newValue) {
        T previous;
        synchronized (mBagOfTags) {
            previous = (T) mBagOfTags.get(key);
            if (previous == null) {
                mBagOfTags.put(key, newValue);
            }
        }
        T result = previous == null ? newValue : previous;
        if (mCleared) {

            closeWithRuntimeException(result);
        }
        return result;
    }

    // Get the added data
    <T> T getTag(String key) {
        if (mBagOfTags == null) {
            return null;
        }
        synchronized (mBagOfTags) {
            return(T) mBagOfTags.get(key); }}private static void closeWithRuntimeException(Object obj) {
        if (obj instanceof Closeable) {
            // Is a subclass of Closeable, close is called.
            try {
                ((Closeable) obj).close();
            } catch (IOException e) {
                throw newRuntimeException(e); }}}}Copy the code

When the ViewModel is cleared, the Tag is cleared and the onCleared method is called to notify the ViewModel that it has been cleared.

Access to the ViewModel

use

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?). {
        / / get the ViewModel
        val model = ViewModelProvider(this).get(MyViewModel::class.java)
        // observe
        model.getUsers().observe(this, Observer<List<User>>{ users ->
            // update UI}}})Copy the code

To get a ViewModel, we need to create the ViewModelProvider, and then call its GET method to get it. Let’s first look at how the ViewModelProvider object is created, and then look at how the GET method is obtained.

ViewModelProvider constructor

ViewModelProvider constructor

public open class ViewModelProvider(
    private val store: ViewModelStore,
    private val factory: Factory
) {
    public constructor(
        owner: ViewModelStoreOwner
    ) : this(owner.viewModelStore, defaultFactory(owner))

    
    public constructor(owner: ViewModelStoreOwner, factory: Factory) : this(
        owner.viewModelStore,
        factory
    )  
}
Copy the code

ViewModelProvider for ViewModel provider, create it needs ViewModelStore and ViewModelProvider. Factory, and ViewModelStore can obtain from ViewModelStoreOwner, Let’s look at each of these classes.

ViewModelStore

ViewModelStore class

public class ViewModelStore {

    / / the ViewModel collection
    private final HashMap<String, ViewModel> mMap = new HashMap<>();
TestViewModel
    // Save the ViewModel. If the key already exists, the value is overwritten, and the previous ViewModel calls the onCleared logic.
    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if(oldViewModel ! =null) { oldViewModel.onCleared(); }}/ / get the ViewModel
    final ViewModel get(String key) {
        return mMap.get(key);
    }

    // Get all keys
    Set<String> keys(a) {
        return new HashSet<>(mMap.keySet());
    }

    // Clear up internal stores and inform ViewModels that they are no longer in use.
    public final void clear(a) {
        for(ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); }}Copy the code

The ViewModelProvider is a ViewModel store that stores or retrieves viewModels, implemented using HashMap. Its clear method clears the internal stores and notifies ViewModels that they are no longer in use.

ViewModelStoreOwner

ViewModelStoreOwner class

public interface ViewModelStoreOwner {

    @NonNull
    ViewModelStore getViewModelStore(a);
}
Copy the code

ViewModelStoreOwner is the owner of ViewModelStore, which can be obtained by subclasses of ViewModelStore. Both activities and fragments on androidx already implement ViewModelStoreOwner. Let’s look at the implementation.

Activity

Androidx.activity.Com ponentActivity class

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        ContextAware.LifecycleOwner.ViewModelStoreOwner.HasDefaultViewModelProviderFactory.SavedStateRegistryOwner.OnBackPressedDispatcherOwner.ActivityResultRegistryOwner.ActivityResultCaller {
        
    private ViewModelStore mViewModelStore;
    
    @NonNull
    @Override
    public ViewModelStore getViewModelStore(a) {
        if (getApplication() == null) {
            // The ViewModel cannot be obtained before the onCreate call
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        / / make sure ViewModelStore
        ensureViewModelStore();
        / / return ViewModelStore
        return mViewModelStore;
    }
    
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    void ensureViewModelStore(a) {
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if(nc ! =null) {
                / / to recover from NonConfigurationInstances ViewModelStore
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                // if mViewModelStore is empty, it will be created.
                mViewModelStore = newViewModelStore(); }}}}Copy the code

Get ViewModelStore androidx Activity, recover from NonConfigurationInstances ViewModelStore (first to ensure the Activity after reconstruction can get ViewModelStore before, How does the ViewModel remain unchanged? , if no, create it.

Description:

  1. androidx ActivityNot in theonCreatecallbeforeTo obtainViewModel.

Fragment

Androidx. Fragments. App. The fragments

public class Fragment implements ComponentCallbacks.OnCreateContextMenuListener.LifecycleOwner.ViewModelStoreOwner.HasDefaultViewModelProviderFactory.SavedStateRegistryOwner.ActivityResultCaller {
        
    @NonNull
    @Override
    public ViewModelStore getViewModelStore(a) {
        if (mFragmentManager == null) {
            Detached ViewModels cannot be accessed from the detached Fragment
            throw new IllegalStateException("Can't access ViewModels from detached fragment");
        }
        if (getMinimumMaxLifecycleState() == Lifecycle.State.INITIALIZED.ordinal()) {
            // When using setMaxLifecycle(INITIALIZED), getViewModelStore() is not supported before the Fragment reaches onCreate()
            throw new IllegalStateException("Calling getViewModelStore() before a Fragment "
                    + "reaches onCreate() when using setMaxLifecycle(INITIALIZED) is not "
                    + "supported");
        }
        return mFragmentManager.getViewModelStore(this); }}Copy the code

FragmentManager –> getViewModelStore method

@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    return mNonConfig.getViewModelStore(f);
}
Copy the code

FragmentManagerViewModel –> getViewModelStore method

@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
    if (viewModelStore == null) {
        viewModelStore = new ViewModelStore();
        mViewModelStores.put(f.mWho, viewModelStore);
    }
    return viewModelStore;
}
Copy the code

FragmentManagerViewModel AndroidX Fragment retrievalViewModelStore androidX Fragment retrievalViewModelStore How does the ViewModel remain unchanged? , and then get it from its mViewModelStores, and if not, create it.

Description:

  1. androidx FragmentNot in theonDetachcallafterTo obtainViewModel.

ViewModelProvider.Factory

ViewModelProvider. Factory class

public interface Factory {

    // Create a new instance of the given ViewModel Class.
    @NonNull
    <T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
Copy the code

ViewModelProvider. Factory for the ViewModel creation Factory, the Factory through the ViewModel class class, create ViewModel instance. Let’s look at its subclasses KeyedFactory, NewInstanceFactory, and AndroidViewModelFactory.

ViewModelProvider.KeyedFactory

ViewModelProvider. KeyedFactory class

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public abstract class KeyedFactory : OnRequeryFactory(), Factory {

    public abstract fun <T : ViewModel> create(
        key: String,
        modelClass: Class<T>): T

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        throw UnsupportedOperationException(
            "create(String, Class
      ) must be called on implementations of KeyedFactory")}}Copy the code

KeyedFactory is an abstract subclass of Factory that overrides create(Class
) method, and the KeyedFactory subclass must override the create(Class
) method and should call its create(String, Class
) method.

ViewModelProvider.NewInstanceFactory

ViewModelProvider. NewInstanceFactory class

public open class NewInstanceFactory : Factory {
    @Suppress("DocumentExceptions")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return try {
            // Get the instance by reflection
            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)
        }
    }

    public companion object {
        private var sInstance: NewInstanceFactory? = null

        / / the singleton NewInstanceFactory
        @JvmStatic
        public val instance: NewInstanceFactory
            @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
            get() {
                if (sInstance == null) {
                    sInstance = NewInstanceFactory()
                }
                returnsInstance!! }}}Copy the code

NewInstanceFactory is a subclass of Factory that implements create(Class
) method to create an instance of ViewModel through the class of the ViewModel class.

Description:

  1. useNewInstanceFactoryTo create theViewModelThere must beNo argumentsandNot privateThe construction method of.
  • Can be handled as followsViewModel:
    • class MyViewModel : ViewModel()
  1. NewInstanceFactory.instanceIs a global singletonNewInstanceFactory, prevents each factory creation and optimizes performance.

ViewModelProvider.AndroidViewModelFactory

ViewModelProvider. AndroidViewModelFactory class

public open class AndroidViewModelFactory(
    private val application: Application
) : NewInstanceFactory() {
    @Suppress("DocumentExceptions")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
            try {
                // This ViewModel is a subclass of AndroidViewModel, passed to Application and created.
                modelClass.getConstructor(Application::class.java).newInstance(application)
            } catch (e: NoSuchMethodException) {
                throw RuntimeException("Cannot create an instance of $modelClass", e)
            } catch (e: IllegalAccessException) {
                throw RuntimeException("Cannot create an instance of $modelClass", e)
            } catch (e: InstantiationException) {
                throw RuntimeException("Cannot create an instance of $modelClass", e)
            } catch (e: InvocationTargetException) {
                throw RuntimeException("Cannot create an instance of $modelClass", e)
            }
        } else super.create(modelClass) // Otherwise, reflection creation of the parent class is performed.
    }

    public companion object {
        // Get the default factory, owner's if owner has a default factory, otherwise NewInstanceFactory (created by reflection).
        internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
            if (owner is HasDefaultViewModelProviderFactory)
                owner.defaultViewModelProviderFactory else instance

        // Get the default Key
        internal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"

        private var sInstance: AndroidViewModelFactory? = null
        
        / / the singleton AndroidViewModelFactory
        @JvmStatic
        public fun getInstance(application: Application): AndroidViewModelFactory {
            if (sInstance == null) {
                sInstance = AndroidViewModelFactory(application)
            }
            returnsInstance!! }}}Copy the code

AndroidViewModelFactory is a subclass of NewInstanceFactory that overrides create(Class
< span style = “box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 14px! Important; word-wrap: inherit! Important;”

Description:

  1. useAndroidViewModelFactoryCreate if thisViewModelisAndroidViewModelSubclass, must haveA referenceAnd isApplicationandNot private(can not be without parameters); Otherwise there has to beNo argumentsandNot privateConstructor of the.
  • Can be handled as followsViewModel:
    • class MyViewModel : ViewModel()
    • class MyViewModel(application: Application) : AndroidViewModel(application)
  1. AndroidViewModelFactory.getInstanceIs a global singletonAndroidViewModelFactory, prevents each factory creation and optimizes performance.

DefaultFactory method to obtain the default factory, if ViewModelStoreOwner subclass also realized HasDefaultViewModelProviderFactory, are provided with the factory, Otherwise, use the NewInstanceFactory factory (create a no-argument ViewModel).

HasDefaultViewModelProviderFactory

HasDefaultViewModelProviderFactory class

public interface HasDefaultViewModelProviderFactory {
    
    // Get the default Factory
    @NonNull
    ViewModelProvider.Factory getDefaultViewModelProviderFactory(a);
}
Copy the code

HasDefaultViewModelProviderFactory tag can get to the default Factory. Has achieved HasDefaultViewModelProviderFactory androidx Activity and fragments, let’s have a look at their specific implementation respectively.

Activity

Androidx.activity.Com ponentActivity class

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        ContextAware,
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner,
        ActivityResultRegistryOwner,
        ActivityResultCaller {
        
    private ViewModelProvider.Factory mDefaultFactory;
    
    @NonNull
    @Override
    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
        if (getApplication() == null) {
            // The ViewModel cannot be obtained before the onCreate call
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        if (mDefaultFactory == null) {
            / / the default factory is empty, is to create SavedStateViewModelFactory, the Application, the current page of the incoming parameters, passed to the constructor.
            mDefaultFactory = new SavedStateViewModelFactory(
                    getApplication(),
                    this, getIntent() ! =null ? getIntent().getExtras() : null);
        }
        returnmDefaultFactory; }}Copy the code

Fragment

Androidx. Fragments. App. The fragments

public class Fragment implements ComponentCallbacks.OnCreateContextMenuListener.LifecycleOwner.ViewModelStoreOwner.HasDefaultViewModelProviderFactory.SavedStateRegistryOwner.ActivityResultCaller {
        
    ViewModelProvider.Factory mDefaultFactory;

    @NonNull
    @Override
    public ViewModelProvider.Factory getDefaultViewModelProviderFactory(a) {
        if (mFragmentManager == null) {
               Detached ViewModels cannot be accessed from the detached Fragment
            throw new IllegalStateException("Can't access ViewModels from detached fragment");
        }
        if (mDefaultFactory == null) {
             / / the default factory is empty, is to create SavedStateViewModelFactory, the Application, the current page of the incoming parameters, passed to the constructor.
            Application application = null;
            Context appContext = requireContext().getApplicationContext();
            while (appContext instanceof ContextWrapper) {
                if (appContext instanceof Application) {
                    application = (Application) appContext;
                    break;
                }
                appContext = ((ContextWrapper) appContext).getBaseContext();
            }
            if (application == null && FragmentManager.isLoggingEnabled(Log.DEBUG)) {
                Log.d(FragmentManager.TAG, "Could not find Application instance from "
                        + "Context " + requireContext().getApplicationContext() + ", you will "
                        + "not be able to use AndroidViewModel with the default "
                        + "ViewModelProvider.Factory");
            }
            / / create SavedStateViewModelFactory
            mDefaultFactory = new SavedStateViewModelFactory(
                    application,
                    this,
                    getArguments());
        }
        returnmDefaultFactory; }}Copy the code

Androidx Activity and the realization of the fragments of the same, SavedStateViewModelFactory is created and the Application, the current page of the incoming parameters, passed to the constructor, Let’s take a look at SavedStateViewModelFactory.

SavedStateViewModelFactory

SavedStateViewModelFactory class

public final class SavedStateViewModelFactory extends ViewModelProvider.KeyedFactory {
    private final Application mApplication;
    private final ViewModelProvider.Factory mFactory;
    private final Bundle mDefaultArgs;
    private final Lifecycle mLifecycle;
    private final SavedStateRegistry mSavedStateRegistry;

    // constructor, no default arguments passed
    public SavedStateViewModelFactory(@Nullable  Application application,
            @NonNull SavedStateRegistryOwner owner) {
        this(application, owner, null);
    }
    
    // the constructor passes the default arguments
    @SuppressLint("LambdaLast")
    public SavedStateViewModelFactory(@Nullable Application application,
            @NonNull SavedStateRegistryOwner owner,
            @Nullable Bundle defaultArgs) { mSavedStateRegistry = owner.getSavedStateRegistry(); mLifecycle = owner.getLifecycle(); mDefaultArgs = defaultArgs; mApplication = application; mFactory = application ! =null
                ? ViewModelProvider.AndroidViewModelFactory.getInstance(application)
                : ViewModelProvider.NewInstanceFactory.getInstance();
    }

    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
        // AndroidViewModel subclass
        boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
        Constructor<T> constructor;
        if(isAndroidViewModel && mApplication ! =null) {
            // Is a subclass of AndroidViewModel that gets the signature constructor (Application, SavedStateHandle)
            constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
        } else {
            // Not a subclass of AndroidViewModel, get (SavedStateHandle) signature constructor
            constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
        }

        if (constructor == null) {
            // If the SavedStateHandle constructor is not available, use mFactory instead.
            return mFactory.create(modelClass);
        }

        // SavedStateHandle is required below
        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            T viewmodel;
            if(isAndroidViewModel && mApplication ! =null) {
                // Reflect the constructor that creates the signature (Application, SavedStateHandle) and pass in SavedStateHandle.
                viewmodel = constructor.newInstance(mApplication, controller.getHandle());
            } else {
                // Reflect the constructor that creates the signature (SavedStateHandle) and pass in SavedStateHandle.
                viewmodel = constructor.newInstance(controller.getHandle());
            }
            viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
            / / return the ViewModel
            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()); }}@NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        / / use the name of the class as the key, create ViewModemLastNonConfigurationInstancesl.
        return create(canonicalName, modelClass);
    }
    
    // (Application, SavedStateHandle) signature
    private static finalClass<? >[] ANDROID_VIEWMODEL_SIGNATURE =new Class[]{Application.class,
            SavedStateHandle.class};
    / / (SavedStateHandle) signature
    private static finalClass<? >[] VIEWMODEL_SIGNATURE =new Class[]{SavedStateHandle.class};

    // Find the signature constructor, no null is returned.
    @SuppressWarnings("unchecked")
    private static <T> Constructor<T> findMatchingConstructor(Class
       
         modelClass, Class
        [] signature)
        {
        for(Constructor<? > constructor : modelClass.getConstructors()) { Class<? >[] parameterTypes = constructor.getParameterTypes();if (Arrays.equals(signature, parameterTypes)) {
                return(Constructor<T>) constructor; }}return null;
    }

    / * * *@hide* /
    @Override
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public void onRequery(@NonNull ViewModel viewModel) { attachHandleIfNeeded(viewModel, mSavedStateRegistry, mLifecycle); }}Copy the code

Androidx creates a default factory for activities and fragments:

  1. androidxtheActivityandFragmentcreateSavedStateViewModelFactoryWhen, are passed inApplicationSo its factorymFactoryforAndroidViewModelFactory.
  2. create(String,Class<*>)Method, ifViewModelIt doesn’t work in the constructorSavedStateHandle, then directly use the factorymFactory(forAndroidViewModelFactory).

Description:

  1. useSavedStateViewModelFactoryCreate if thisViewModelIt doesn’t work in the constructorSavedStateHandleIs directly usedAndroidViewModelFactoryCreate; If used, reflection is created(Application, SavedStateHandle)or(SavedStateHandle)Signature constructor.
  • Can be handled as followsViewModel:
    • class MyViewModel : ViewModel()
    • class MyViewModel(application: Application) : AndroidViewModel(application)
    • class MyViewModel(val handle: SavedStateHandle) : ViewModel()
    • class MyViewModel(application: Application, val handle: SavedStateHandle) : AndroidViewModel(application)
  1. Due to theSavedStateHandleIs passed to the current pageParameter passed in, so throughSavedStateHandleYou can also get the current pageParameter passed in.
  2. useSavedStateHandleRelevant, will be inJetpact- Save stateTo explain in detail.

Having said the creation of the ViewModelProvider object, let’s look at how its get() method gets the ViewModel.

ViewModelProvider. The get method

ViewModelProvider – > the get method

@MainThread
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
    // Get the class name
    valcanonicalName = modelClass.canonicalName ? :throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
    // Use the default name + class name as key to get the ViewModel.
    return get("$DEFAULT_KEY:$canonicalName", modelClass)
}

@Suppress("UNCHECKED_CAST")
@MainThread
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
    // Get the ViewModel from the ViewModelStore
    var viewModel = store[key]
    if (modelClass.isInstance(viewModel)) {
        // viewModel is not empty and is the target class, which returns directly.
        (factory as? OnRequeryFactory)? .onRequery(viewModel)return viewModel as T
    } else {
        @Suppress("ControlFlowWithEmptyBody")
        if(viewModel ! =null) {
            // TODO: log a warning.}}// If no ViewModel is found, create it directly and store it in ViewModelStore.
    viewModel = if (factory is KeyedFactory) {
        // Is a subclass of KeyedFactory that calls create(key, modelClass) directly.
        factory.create(key, modelClass)
    } else {
        factory.create(modelClass)
    }
    // Store it in ViewModelStore
    store.put(key, viewModel)
    return viewModel
}
Copy the code

Viewmodelprovider.get code flow:

  1. get(Class<*>)Method, usingDefault name + class nameAs akey, the callget(String, Class<*>)Method, obtainViewModel.
  2. get(String, Class<*>)Method, first fromViewModelStoreTo deriveViewModelIf theThere are and are target classes, returns directly, otherwise usesFactoryCreate it directly and save it toViewModelStoreTo be obtained later.

conclusion

Take the Activity on AndroidX to get the ViewModel constructor without arguments as an example to explain the code flow.

Declare the ViewModel

class MyViewModel : ViewModel() {

    override fun onCleared(a) {
        super.onCleared()
    }
}
Copy the code

Access to the ViewModel

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?). {
        / / get the ViewModel
        val model = ViewModelProvider(this).get(MyViewModel::class.java)      
    }
}
Copy the code

Sample code flow:

  1. createViewModelProviderThe incoming isComponentActivity, it’sViewModelStoreforComponentActivityTo provide theViewModelStore, it’sFactoryforComponentActivityThe default factory providedSavedStateViewModelFactory.
  2. get()Method, first fromViewModelStoreTo deriveViewModelIf theThere are and are target classes, returns directly, otherwise usesFactory(SavedStateViewModelFactory) directly create and save toViewModelStoreTo be obtained later.
  3. SavedStateViewModelFactorythecreate()Method is called directlyAndroidViewModelFactorythecreate()Methods. (Because of the acquisitionMyViewModelDon’t useSavedStateHandle, so it calls directlymFactoryCreation. And because of creatingSavedStateViewModelFactoryWhen introduced into theApplication, somFactoryforAndroidViewModelFactory)
  4. AndroidViewModelFactorythecreate()Method will be used directlyreflectioncreateNo argumentsConstructor. (Because of the acquisitionMyViewModelNo inheritanceAndroidViewModel, so it goes to the parent classNewInstanceFactoryLogical creation of

ViewModel lifecycle

Why the ViewModel life cycle is longer than the Activity and Fragment life cycle, how it stays the same, and how it is removed, let’s examine them separately.

How does the ViewModel stay the same?

Activities and fragments are destroyed and recreated in the event of a configuration change (such as a screen rotation), but the reacquired ViewModel instance remains the same. In reverse analysis, to keep the ViewModel instance unchanged, you need to keep the ViewModelStore unchanged. Let’s take a look at the getViewModelStore() methods of the Activity and Fragment on androidx.

Activity

ComponentActivity – > getViewModelStore method

@NonNull
@Override
public ViewModelStore getViewModelStore(a) {
    if (getApplication() == null) {
        // The ViewModel cannot be obtained before the onCreate call
        throw new IllegalStateException("Your activity is not yet attached to the "
                + "Application instance. You can't request ViewModel before onCreate call.");
    }
    / / make sure ViewModelStore
    ensureViewModelStore();
    / / return ViewModelStore
    return mViewModelStore;
}

@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore(a) {
    if (mViewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if(nc ! =null) {
            / / to recover from NonConfigurationInstances ViewModelStore
            mViewModelStore = nc.viewModelStore;
        }
        if (mViewModelStore == null) {
            // if mViewModelStore is empty, it will be created.
            mViewModelStore = newViewModelStore(); }}}Copy the code

Get ViewModelStore, we first obtained from the NonConfigurationInstances, its internal contains a ViewModelStore member variables, . Let’s analyse NonConfigurationInstances viewModelStore how the assignment, and then to analyze how to get to it.

Description:

  1. whyComponentActivitythemViewModelStoreProperties,Before the configuration changeStore value while inAfter configuration changesIs empty?
  • becauseActivityinAfter configuration changes, recreatedActivity.ActivityObject is new, so it’smViewModelStoreProperty is the initial state: empty.

ComponentActivity. NonConfigurationInstances class

static final class NonConfigurationInstances {
    Object custom;
    ViewModelStore viewModelStore;
}
Copy the code

By looking for reference, NonConfigurationInstances viewModelStore is in ComponentActivity onRetainNonConfigurationInstance () method to complete the assignment.

ComponentActivity – > onRetainNonConfigurationInstance method

public final Object onRetainNonConfigurationInstance(a) {
    // Maintain backward compatibility.
    Object custom = onRetainCustomNonConfigurationInstance();

    ViewModelStore viewModelStore = mViewModelStore;
    if (viewModelStore == null) {
        / / viewModelStore is empty, then this time did not call getViewModelStore (), by getLastNonConfigurationInstance () from before reconstruction.
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if(nc ! =null) { viewModelStore = nc.viewModelStore; }}if (viewModelStore == null && custom == null) {
        return null;
    }

    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    // Record the current viewModelStore to complete the assignment operation.
    nci.viewModelStore = viewModelStore;
    return nci;
}
Copy the code

This method, create ComponentActivity NonConfigurationInstances object, record the current viewModelStore, and returns the object.

Description:

  1. Overrides the parent classActivitytheonRetainNonConfigurationInstance()Method to make it createdComponentActivity.NonConfigurationInstancesIn object,After configuration changesNot affected.
  2. ComponentActivity.NonConfigurationInstances.viewModelStoreProperty, saved inBefore the configuration changeMaintenance of theViewModelStore.

By looking for references, ComponentActivity onRetainNonConfigurationInstance () method is the Activity of retainNonConfigurationInstances invoke () method.

The Activity – > retainNonConfigurationInstances method

NonConfigurationInstances retainNonConfigurationInstances(a) {
    // Get the data to save for the current activity
    Object activity = onRetainNonConfigurationInstance();
    HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
    FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();

    // We're already stopped but we've been asked to retain.
    // Our fragments are taken care of but we need to mark the loaders for retention.
    // In order to do this correctly we need to restart the loaders first before
    // handing them off to the next activity.
    mFragments.doLoaderStart();
    mFragments.doLoaderStop(true);
    ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();

    if (activity == null && children == null && fragments == null && loaders == null
            && mVoiceInteractor == null) {
        return null;
        
    NonConfigurationInstances nci = new NonConfigurationInstances();
    // Record the current activity data to complete the assignment.
    nci.activity = activity;
    nci.children = children;
    nci.fragments = fragments;
    nci.loaders = loaders;
    if(mVoiceInteractor ! =null) {
        mVoiceInteractor.retainInstance();
        nci.voiceInteractor = mVoiceInteractor;
    }
    return nci;
}
Copy the code

This method, create Activity. NonConfigurationInstances object, record its Activity to save the data (i.e. ComponentActivity. NonConfigurationInstances object), and returns the object.

Description:

  1. ActivitytheretainNonConfigurationInstances()Method to make it createdActivity.NonConfigurationInstancesIn object,After configuration changesNot affected.
  2. Activity.NonConfigurationInstances.activity Property, savedComponentActivity.NonConfigurationInstancesObject.

Through the global search, the Activity. RetainNonConfigurationInstances () method is in ActivityThread performDestroyActivity invoke () method.

ActivityThread – > performDestroyActivity method

void performDestroyActivity(ActivityClientRecord r, boolean finishing,
        int configChanges, boolean getNonConfigInstance, String reason) {...if (getNonConfigInstance) {
        try {
            / / the Activity was obtained from the Activity of ActivityClientRecord. NonConfigurationInstances object,
            / / and then save it lastNonConfigurationInstances, complete the save operation.
            r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
        } catch (Exception e) {
            if(! mInstrumentation.onException(r.activity, e)) {throw new RuntimeException("Unable to retain activity "
                        + r.intent.getComponent().toShortString() + ":"+ e.toString(), e); }}}...// Call back the Activity's onDestroy methodmInstrumentation.callActivityOnDestroy(r.activity); . }Copy the code

When the Activity is destroyed, Will first will not change as a result of configuration changes data (i.e. the Activity. NonConfigurationInstances) saved to ActivityClientRecord lastNonConfigurationInstances attributes.

Description:

  1. ActivityThread: it managementThe applicationIn the process ofThe main threadExecution, scheduling, and execution ofactivity, broadcasting andactivity managerAdditional operations requested.
  2. ActivityClientRecord:ActivityClient record, for realActivityThe bookkeeping of instances.
  3. ActivityClientRecord.lastNonConfigurationInstances.activity.viewModelStoreProperty, saved inBefore the configuration changeMaintenance of theViewModelStore.

Next, let’s take a look at is if you get to keep the maintenance of ViewModelStore before configuration changes, let’s take a look at the Activity. The getLastNonConfigurationInstance () method.

The Activity – > getLastNonConfigurationInstance method

@Nullable
public Object getLastNonConfigurationInstance(a) {
    returnmLastNonConfigurationInstances ! =null
            ? mLastNonConfigurationInstances.activity : null;
}
Copy the code

MLastNonConfigurationInstances for Activity. NonConfigurationInstances, getLastNonConfigurationInstance () results back its Activity attribute, Namely ComponentActivity NonConfigurationInstances object.

Let’s see, where is mLastNonConfigurationInstances for assignment. By looking for mLastNonConfigurationInstances is the Activity of the attach () in the assignment.

The Activity – > attach method

@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
        IBinder shareableActivityToken) {...// Complete the assignmentmLastNonConfigurationInstances = lastNonConfigurationInstances; . }Copy the code

Through the global search, the Activity. RetainNonConfigurationInstances () method is in ActivityThread performDestroyActivity invoke () method.

ActivityThread – > performLaunchActivity method

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {.../ / call the attach, the incoming ActivityClientRecord lastNonConfigurationInstances.
            activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback, r.assistToken, r.shareableActivityToken); .return activity;
}
Copy the code

When the Activity starts, its attach() method is called, The incoming ActivityClientRecord. LastNonConfigurationInstances preservation Activity. NonConfigurationInstances object.

Description:

  1. whyActivityThreadtheperformLaunchActivity(),performDestroyActivity()Methods the insideActivityClientRecordIs it the same?
  • becauseActivityClientRecordStored in theActivityThread.mActivitiesProperty, which isActivityClientRecordtheMapThe collection,ActivityClientRecordinstartActivityNow()Method is created and calledperformLaunchActivity()Method within which the createdActivityClientRecordObject, so it can be accessed fromMapTo retrieve the previously savedActivityClientRecord, soperformLaunchActivity(),performDestroyActivity()Methods the insideActivityClientRecordIt’s the same.

Code flow:

  1. inActivityThread.performDestroyActivity()Method,ActivityClientRecord.lastNonConfigurationInstancesSave theActivity.retainNonConfigurationInstances()Method returnActivity.NonConfigurationInstancesObject.
  2. One of theActivity.NonConfigurationInstances.activityProperty, savedComponentActivity.onRetainNonConfigurationInstance()Method returnComponentActivity.NonConfigurationInstancesObject.
  3. One of theComponentActivity.NonConfigurationInstances.viewModelStoreProperty, saved inBefore the configuration changeMaintenance of theViewModelStore.
  4. inActivityThread.performLaunchActivity()Method, callActivity.attach()The method passed in is saved inActivityClientRecord.lastNonConfigurationInstancestheActivity.NonConfigurationInstancesObject.
  5. Activity.attach()Method that saves the incomingActivity.NonConfigurationInstancesObject.
  6. By calling theActivity.getLastNonConfigurationInstance()Method, can getActivity.NonConfigurationInstances.activityAttribute savedComponentActivity.NonConfigurationInstancesObject.
  7. Finally getComponentActivity.NonConfigurationInstances.viewModelStoreThe value of the property is immediately availableComponentActivitytheViewModelStoreObject.

Conclusion:

  1. inActivityWhen it was destroyed,ActivityClientRecord.lastNonConfigurationInstances.activity.viewModelStoreProperty, saved inBefore the configuration changeMaintenance of theViewModelStore.
  2. inActivityWhen it starts up,ActivityClientRecord.lastNonConfigurationInstancesThe value of theActivity.attach()Was deposited inActivity, so the follow-up can also be obtained inBefore the configuration changeMaintenance of theViewModelStore, soBefore and after configuration ChangeTo get toViewModelStore,ViewModelExamples of the same.

Fragment

@NonNull
@Override
public ViewModelStore getViewModelStore(a) {
    if (mFragmentManager == null) {
	Detached ViewModels cannot be accessed from the detached Fragment
        throw new IllegalStateException("Can't access ViewModels from detached fragment");
    }
    if (getMinimumMaxLifecycleState() == Lifecycle.State.INITIALIZED.ordinal()) {
        throw new IllegalStateException("Calling getViewModelStore() before a Fragment "
                + "reaches onCreate() when using setMaxLifecycle(INITIALIZED) is not "
                + "supported");
    }
    return mFragmentManager.getViewModelStore(this);
}
Copy the code

MFragmentManager is FragmentManager, and let’s look at its getViewModelStore() method.

FragmentManager –> getViewModelStore method

@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    return mNonConfig.getViewModelStore(f);
}
Copy the code

MNonConfig is FragmentManagerViewModel. Let’s first look at how it was created and then look at its getViewModelStore() method.

By looking for, found the FragmentManager. AttachController create () method.

FragmentManager –> attachController method

@SuppressWarnings("deprecation")
@SuppressLint("SyntheticAccessor")
void attachController(@NonNullFragmentHostCallback<? > host,@NonNull FragmentContainer container, @Nullable final Fragment parent) {...// Get the FragmentManagerViewModel
    if(parent ! =null) {
        // If parent is not null, call getChildNonConfig of parent FragmentManager.
        mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
    } else if (host instanceof ViewModelStoreOwner) {
        // Get the ViewModelStore from host and then use FragmentManagerViewModel.
        ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
        mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
    } else {
        mNonConfig = new FragmentManagerViewModel(false); }... }Copy the code

By looking up, I found attachController method will call, when fragments of the attach one host for FragmentActivity inner class FragmentActivity. HostCallbacks, It implements the ViewModelStoreOwner interface.

Create mNonConfig. If there is no parent Fragment, getViewModelStore from host by calling getViewModelStore(). Then call FragmentManagerViewModel. GetInstance (viewModelStore) to obtain FragmentManagerViewModel.

Generally because there is no father Fragment, second if most go, so let’s analyze it, let’s take a look at FragmentActivity. The HostCallbacks getViewModelStore () method, Then look at the FragmentManagerViewModel’s getInstance() method.

FragmentActivity. HostCallbacks – > getViewModelStore method

class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements
        ViewModelStoreOwner.OnBackPressedDispatcherOwner.ActivityResultRegistryOwner.SavedStateRegistryOwner.FragmentOnAttachListener {...@NonNull
    @Override
    public ViewModelStore getViewModelStore(a) {
        return FragmentActivity.this.getViewModelStore(); }... }Copy the code

FragmentActivity. HostCallbacks getViewModelStore () method, direct call the FragmentActivity getViewModelStore () method, That is, the getViewModelStore() method of its parent ComponentActivity is called.

So FragmentManager. AttachController () method, through the host also can get ComponentActivity ViewModelStore.

Next, let’s look at the getInstance() method of FragmentManagerViewModel.

FragmentManagerViewModel –> getInstance method

final class FragmentManagerViewModel extends ViewModel {
    private static final String TAG = FragmentManager.TAG;

    private static final ViewModelProvider.Factory FACTORY = new ViewModelProvider.Factory() {
        @NonNull
        @Override
        @SuppressWarnings("unchecked")
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            FragmentManagerViewModel viewModel = new FragmentManagerViewModel(true);
            return(T) viewModel; }};@NonNull
    static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
        ViewModelProvider viewModelProvider = new ViewModelProvider(viewModelStore,
                FACTORY);
        returnviewModelProvider.get(FragmentManagerViewModel.class); }}Copy the code

FragmentManagerViewModel is a ViewModel, The getInstance(ViewModelStore) method will first get from the ViewModelStore that’s passed in, If not, use FACTORY to create the FragmentManagerViewModel.

Description:

  1. The incomingViewModelStoreforComponentActivitytheViewModelStoreAt firstViewModelStoreInside there is noFragmentManagerViewModel, so createFragmentManagerViewModelAnd in theComponentActivitytheViewModelStoreIn the.
  2. Due to theComponentActivitytheViewModelStoreAfter configuration changesThe instance doesn’t change, soFragmentManagerViewModel.getInstance()Methods can also be derived fromComponentActivitytheViewModelStoreGet to theBefore configuration ChangeThe depositFragmentManagerViewModelThe instance.

Having said the creation of FragmentManagerViewModel, let’s look at its getViewModelStore() method.

FragmentManagerViewModel –> getViewModelStore method

@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
    if (viewModelStore == null) {
        viewModelStore = new ViewModelStore();
        mViewModelStores.put(f.mWho, viewModelStore);
    }
    return viewModelStore;
}
Copy the code

GetViewModelStore (Fragment) method, obtain the specified Fragment ViewModelStore, if not, create and save to mViewModelStores. MViewModelStores is a Map collection of ViewModelStores.

Description:

  1. whyFragmentManagerViewModel.getViewModelStore(Fragment)Method to pass inFragmentIn order to obtainViewModelStore?
  • becauseFragmentManagerViewModel, saved toComponentActivitytheViewModelStoreIn, so eachFragmentTo get toFragmentManagerViewModelInstances of the same, so we need to pass inFragmentThe instance distinction is acquisitionViewModelStoreA collection ofOf which.
  1. whyFragmentinBefore and after configuration ChangeTo get toViewModelStore,ViewModelExamples of the same?
  • becauseComponentActivityinBefore and after configuration ChangeTo get toViewModelStore,ViewModelExamples of the sameSo there isComponentActivitytheViewModelStoreIn theFragmentManagerViewModelExamples of the sameSo there ismViewModelStoresEach of theFragmenttheViewModelStoreExamples of the same, soViewModelExamples of the same.

Code flow:

  1. FragmenttheattachWhen, to obtainComponentActivitytheViewModelStoreTo createFragmentManagerViewModelAnd in theComponentActivitytheViewModelStoreIn the.
  2. FragmentManagerViewModel.getViewModelStore(Fragment)By means ofFragmentfrommViewModelStoresTo obtain the correspondingViewModelStoreIf no, create a file and save the file tomViewModelStoresIn the.

How is the ViewModel cleared?

To analyze how the ViewModel is cleared, you need to analyze how the ViewModelStore is cleared.

Activity

A reference lookup shows that the ViewModelStore cleanup operation is called in the Constructor for ComponentActivity.

ComponentActivity class

public ComponentActivity(a) {
    Lifecycle lifecycle = getLifecycle();
    //noinspection ConstantConditions
    if (lifecycle == null) {
        throw new IllegalStateException("getLifecycle() returned null in ComponentActivity's "
                + "constructor. Please make sure you are lazily constructing your Lifecycle "
                + "in the first call to getLifecycle() rather than relying on field "
                + "initialization."); }... getLifecycle().addObserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                // Clear out the available context
                mContextAwareHelper.clearAvailableContext();
                // And clear the ViewModelStore
                if(! isChangingConfigurations()) {// Clear all viewModels instead of configuration changes.getViewModelStore().clear(); }}}}); . }Copy the code

Lifecycle is used to observe the state of the current Lifecycle, and if the event is ON_DESTROY and not a configuration change, empty all viewmodels.

Description:

  1. ActivitytheViewModelHow was it removed?
  • useLifecycleObserve the status of the current lifecycle, if the event isON_DESTROYandNot a configuration change, empty allViewModel.

Fragment

By reference, we found that in FragmentManagerViewModel clearNonConfigStateInternal method calls the ViewModelStore removal operations.

FragmentManagerViewModel – > clearNonConfigStateInternal method

void clearNonConfigState(@NonNull Fragment f) {
    if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
        Log.d(TAG, "Clearing non-config state for " + f);
    }
    clearNonConfigStateInternal(f.mWho);
}

void clearNonConfigState(@NonNull String who) {
    if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
        Log.d(TAG, "Clearing non-config state for saved state of Fragment " + who);
    }
    clearNonConfigStateInternal(who);
}

private void clearNonConfigStateInternal(@NonNull String who) {
    // Clear and remove the Fragment's child non config state
    FragmentManagerViewModel childNonConfig = mChildNonConfigs.get(who);
    if(childNonConfig ! =null) {
        childNonConfig.onCleared();
        mChildNonConfigs.remove(who);
    }
    // Clear and remove the Fragment's ViewModelStore
    // Obtain the corresponding Fragment ViewModelStore
    ViewModelStore viewModelStore = mViewModelStores.get(who);
    if(viewModelStore ! =null) {
	// Clear all viewModels.viewModelStore.clear(); mViewModelStores.remove(who); }}Copy the code

ClearNonConfigStateInternal (String) method, can get to the corresponding ViewModelStore fragments, and then call the clear () method to remove all the ViewModel.

Through the reference, we found that in clearNonConfigStateInternal (String) method is clearNonConfigState (fragments), clearNonConfigState (String) method calls, Then it is two and several calls, and finally through the Debug found FragmentStateManager. Destroy () method, performs a clearNonConfigState (fragments) method.

FragmentStateManager –> destroy method

void destroy(a) {...if(shouldDestroy) { FragmentHostCallback<? > host = mFragment.mHost;boolean shouldClear;
        if (host instanceof ViewModelStoreOwner) {
            shouldClear = mFragmentStore.getNonConfig().isCleared();
        } else if (host.getContext() instanceofActivity) { Activity activity = (Activity) host.getContext(); shouldClear = ! activity.isChangingConfigurations(); }else {
            shouldClear = true;
        }
        if((beingRemoved && ! mFragment.mBeingSaved) || shouldClear) {// Run clearNonConfigState(Fragment) of FragmentManagerViewModel to clear the state that will not change due to configuration changes.mFragmentStore.getNonConfig().clearNonConfigState(mFragment); }... }... }Copy the code

Host for FragmentActivity HostCallbacks, it implements the ViewModelStoreOwner interface, so will walk first the if. Whenever shouldClear is true, the clearNonConfigState(Fragment) method of FragmentManagerViewModel is executed, What is the return value of the isCleared() method of the FragmentManagerViewModel?

FragmentManagerViewModel –> isCleared method

final class FragmentManagerViewModel extends ViewModel {

    @Override
    protected void onCleared(a) {
        if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
            Log.d(TAG, "onCleared called for " + this);
        }
        // The tag has been cleared
        mHasBeenCleared = true;
    }

    boolean isCleared(a) {
        returnmHasBeenCleared; }}Copy the code

FragmentManagerViewModel is a ViewModel that’s added to the ViewModelStore for ComponentActivity, The onCleared() method of ViewModel is called when the ViewModelStore for ComponentActivity is cleared (the event is ON_DESTROY and not a configuration change), then mHasBeenCleared is true, The isCleared() method returns true.

Because isCleared () method returns true, so FragmentStateManager. Destroy () method is executed within the FragmentManagerViewModel clearNonConfigState (fragments) method, The Fragment’s ViewModelStore is retrieved and its clear() method is called to clear all viewModels.

Description:

  1. FragmenttheViewModelHow was it removed?
  • FragmentManagerViewModelIs aViewModel, has been added toComponentActivitytheViewModelStoreWhen theComponentActivitytheViewModelStoreWhen cleared (the event isON_DESTROYandNot a configuration change), will callViewModeltheonCleared()Methods,mHasBeenClearedfortrue, i.e.,isCleared()Method returnstrue, soFragmentStateManager.destroy()Method is executedFragmentManagerViewModeltheclearNonConfigState(Fragment)Method, and you get the correspondingFragmenttheViewModelStoreAnd then call itclear()methodsRemove allViewModel.

conclusion

That’s the full jetpack-ViewModel source code! Jetpack’s other source code series will be published later, please stay tuned. If you have any questions, see you in the comments!

Finally, I would like to recommend my website, devbolg.cn, the developer’s technical blog, which currently contains android related technologies, and will be open to all developers later. Welcome to experience!