ViewModel的使用场景
Activity or Fragment为Controller
场景一、Controller配置变化导致其重建 若需要保证Controller转屏前后的数据一致性,传统的方法需要我们在onSaveInstance保存数据,复杂类型的数据还必须实现Parcelable接口。使用ViewModel去维护数据则可以解决这个问题,ViewModel为我们在重建的时候保存了数据。
场景二、多Controler共享数据 若要实现Activity和Fragment之间的做法,我们常用的方法有:SharedPreference、Database、全局变量、两者之间回调。这些实现会随着业务规模的扩大,变得难以维护,且不易独立进行测试。ViewModel独立于两者之间,只有两者共同维护一个ViewModel实例,就能轻松实现共享数据,而且ViewModel是与生命周期绑定的,不用去手动销毁。
ViewModel的原理
如图所示:
所有已经实例化的ViewModel缓存在ViewModelStore中,其实质就是一个HashMap;
ViewModerStore与具体的Controller绑定,并与宿主 Controller 俱生俱灭,所以这就解释了为何 ViewModel 与宿主 Controller 的生命周期是一样长了,因为缓存它的 ViewModelStore 与宿主 Controller 寿命相等;
获取ViewModel实例的方法委托给了ViewModerProvider, 若缓存中有则直接得到,若没有才创建并缓存;
源码分析 获取ViewModel的过程 1 2 3 4 5 6 7 8 9 10 11 public ViewModelProvider (@NonNull ViewModelStore store, @NonNull Factory factory) { mFactory = factory; mViewModelStore = store; } public class ViewModelStore { private final HashMap<String, ViewModel> mMap = new HashMap <>(); }
可以看到ViewModelProvider持有了ViewModelStore,而在ViewModelStore内部通过一个HashMap去维护ViewModel缓存。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 @NonNull @MainThread 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); } @NonNull @MainThread public <T extends ViewModel > T get (@NonNull String key, @NonNull Class<T> modelClass) { ViewModel viewModel = mViewModelStore.get(key); if (modelClass.isInstance(viewModel)) { if (mFactory instanceof OnRequeryFactory) { ((OnRequeryFactory) mFactory).onRequery(viewModel); } return (T) viewModel; } else { if (viewModel != null ) { } } if (mFactory instanceof KeyedFactory) { viewModel = ((KeyedFactory) mFactory).create(key, modelClass); } else { viewModel = mFactory.create(modelClass); } mViewModelStore.put(key, viewModel); return (T) viewModel; }
接下来看看工厂具体创建ViewModel的过程, 默认的工厂是SavedStateViewModelFactory。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public final class SavedStateViewModelFactory extends ViewModelProvider .KeyedFactory { public <T extends ViewModel > T create (@NonNull String key, @NonNull Class<T> modelClass) { boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass); Constructor<T> 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); 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; } } }
ViewModel与宿主生命周期保持一致的原理 前面我们说ViewModel与ViewModel与宿主生命周期保持一致,其中原理是什么。
ViewModelStore树