In MVVM architecture, viewModel instantiation is implemented through ViewModel providers via the Create method of NewInstanceFactory in the following two ways:
/ / use the default ViewModelProvider. NewInstanceFactory ViewModelProviders. Of (this). The get (getViewModel ()); / / use custom ViewModelProvider NewInstanceFactory ViewModelProviders.of(this,MainViewModelFactory.getInstance(application)).get(getViewModel());Copy the code
The Create method instantiates the viewModel, passing the parameters Application and Model, and instantiates Model as well
public class MainViewModelFactory extends ViewModelProvider.NewInstanceFactory { @SuppressLint("StaticFieldLeak") private static volatile MainViewModelFactory INSTANCE; private final Application mApplication; public static MainViewModelFactory getInstance(Application application) { if (INSTANCE == null) { synchronized (MainViewModelFactory.class) { if (INSTANCE == null) { INSTANCE = new MainViewModelFactory(application); } } } return INSTANCE; } private MainViewModelFactory(Application application) { this.mApplication = application; } @VisibleForTesting public static void destroyInstance() { INSTANCE = null; } @NonNull @Override public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { if (modelClass.isAssignableFrom(MainViewModel.class)) { return (T) new MainViewModel(mApplication, new MainModel(mApplication)); } throw new IllegalArgumentException("Unknown ViewModel class: " + modelClass.getName()); }}Copy the code
// Model can also be instantiated in viewModel via generics + reflection
public class BaseViewModel<M extends BaseModel> extends ViewModel { public M model; public BaseViewModel() { try { ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass(); Class<M> modelClazz = (Class<M>) type.getActualTypeArguments()[0]; model = modelClazz.newInstance(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); }}}Copy the code
Let’s see how the viewModel is instantiated step by step in the source code. Okay
1. Instantiate ViewModelProvider in ViewModelProviders
public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) { Application application = checkApplication(activity); if (factory == null) { factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); } // You can see that the ViewModelStore is bound to the activity, so the viewModel is a reusable return new in the same activity ViewModelProvider(activity.getViewModelStore(), factory); }Copy the code
2. The ViewModelProvider get method first spells out the key using the class name of the ViewModel
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) { String canonicalName = modelClass.getCanonicalName(); if (canonicalName == null) { throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels"); } return get(DEFAULT_KEY + ":" + canonicalName, modelClass); }Copy the code
3. Then instantiate the ViewModel through the Factory create method, and store it in mViewModelStore with the key identifier. Next time, you can directly obtain it from mViewModelStore with the key
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) { ViewModel viewModel = mViewModelStore.get(key); if (modelClass.isInstance(viewModel)) { //noinspection unchecked 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); //noinspection unchecked return (T) viewModel; }Copy the code