可以看到 ViewModel 并不是简单地 new 出来的,这其中的逻辑要需要我们一步一步慢慢揭开。
那么 ViewModel 是怎样被定义的呢?
ViewModel
1 2 3 4 5 6 7 8 9 10 11
publicabstractclassViewModel { /** * This method will be called when this ViewModel is no longer used and will be destroyed. * <p> * It is useful when ViewModel observes some data and you need to clear this subscription to * prevent a leak of this ViewModel. */ @SuppressWarnings("WeakerAccess") protectedvoidonCleared() { } }
publicinterfaceFactory { /** * Creates a new instance of the given {@code Class}. * <p> * * @param modelClass a {@code Class} whose instance is requested * @param <T> The type parameter for the ViewModel. * @return a newly created ViewModel */ @NonNull <T extendsViewModel> T create(@NonNull Class<T> modelClass); }
/** * {@link Factory} which may create {@link AndroidViewModel} and * {@link ViewModel}, which have an empty constructor. */ publicstaticclassAndroidViewModelFactoryextendsViewModelProvider.NewInstanceFactory {
privatestatic AndroidViewModelFactory sInstance;
/** * Retrieve a singleton instance of AndroidViewModelFactory. * * @param application an application to pass in {@link AndroidViewModel} * @return A valid {@link AndroidViewModelFactory} */ @NonNull publicstatic AndroidViewModelFactory getInstance(@NonNull Application application) { if (sInstance == null) { sInstance = newAndroidViewModelFactory(application); } return sInstance; }
private Application mApplication;
/** * Creates a {@code AndroidViewModelFactory} * * @param application an application to pass in {@link AndroidViewModel} */ publicAndroidViewModelFactory(@NonNull Application application) { mApplication = application; }
@NonNull @Override public <T extendsViewModel> T create(@NonNull Class<T> modelClass) { if (AndroidViewModel.class.isAssignableFrom(modelClass)) { //noinspection TryWithIdenticalCatches try { return modelClass.getConstructor(Application.class).newInstance(mApplication); } catch (NoSuchMethodException e) { thrownewRuntimeException("Cannot create an instance of " + modelClass, e); } catch (IllegalAccessException e) { thrownewRuntimeException("Cannot create an instance of " + modelClass, e); } catch (InstantiationException e) { thrownewRuntimeException("Cannot create an instance of " + modelClass, e); } catch (InvocationTargetException e) { thrownewRuntimeException("Cannot create an instance of " + modelClass, e); } } returnsuper.create(modelClass); } }
/** * Returns the {@link ViewModelStore} of the given activity. * * @param activity an activity whose {@code ViewModelStore} is requested * @return a {@code ViewModelStore} */ @NonNull @MainThread publicstatic ViewModelStore of(@NonNull FragmentActivity activity) { if (activity instanceof ViewModelStoreOwner) { return ((ViewModelStoreOwner) activity).getViewModelStore(); } return holderFragmentFor(activity).getViewModelStore(); }
/** * Returns the {@link ViewModelStore} of the given fragment. * * @param fragment a fragment whose {@code ViewModelStore} is requested * @return a {@code ViewModelStore} */ @NonNull @MainThread publicstatic ViewModelStore of(@NonNull Fragment fragment) { if (fragment instanceof ViewModelStoreOwner) { return ((ViewModelStoreOwner) fragment).getViewModelStore(); } return holderFragmentFor(fragment).getViewModelStore(); } }
根据 ViewModelProviders 的思路,ViewModelStores 也是分为了两个方法,对应着 Fragment 和 Activity 。
如果 Activity 和 Fragment 实现了 ViewModelStoreOwner 的接口,那么直接返回内部的 ViewModelStore 就行了;
如果是之前老早版本的 Activity 或者 Fragment ,那么它们肯定是没有实现 ViewModelStoreOwner 接口的,那该怎么办呢?很简单,新创建一个 Fragment 来关联 ViewModelStoreOwner 就好了啊!
@NonNull @MainThread public <T extendsViewModel> T get(@NonNull Class<T> modelClass) { StringcanonicalName= modelClass.getCanonicalName(); if (canonicalName == null) { thrownewIllegalArgumentException("Local and anonymous classes can not be ViewModels"); } return get(DEFAULT_KEY + ":" + canonicalName, modelClass); }
@NonNull @MainThread public <T extendsViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) { ViewModelviewModel= mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) { //noinspection unchecked return (T) viewModel; } else { //noinspection StatementWithEmptyBody if (viewModel != null) { // TODO: log a warning. } }
/** * Clears internal storage and notifies ViewModels that they are no longer used. */ publicfinalvoidclear() { for (ViewModel vm : mMap.values()) { vm.onCleared(); } mMap.clear(); }
/** * Called when the fragment is no longer in use. This is called * after {@link #onStop()} and before {@link #onDetach()}. */ @CallSuper publicvoidonDestroy() { mCalled = true; // Use mStateSaved instead of isStateSaved() since we're past onStop() if (mViewModelStore != null && !mHost.mFragmentManager.mStateSaved) { mViewModelStore.clear(); } }