文章目录
- 前言
- 源码分析
- ViewModel是如何创建的?
- ViewModelProvider(this)做了什么?
- 小结
- get(MyViewModel::class.java)做了什么?
- 小结
- ViewModel是如何实现配置更改后数据恢复的?
- 整体时序图
- 结语
前言
本文主要分析ViewModel
相关源码,相关使用不再赘述,可参考Android ViewModel使用;
ViewModel 概览
Google官方给的ViewModel
定义如下:
ViewModel类旨在`以注重生命周期的方式存储和管理界面相关数据`。ViewModel类`让数据可在发生屏幕旋转等配置更改后继续留存`。
定义主要提到两个关键点:
-
生命周期
上图是Google官网提供的ViewModel生命周期图示
,可以看到ViewModel
的生命周期是从onCreate
创建到完成并销毁Finished
,开发中经常结合LiveData
一起使用; -
配置更改后数据留存
我们知道当屏幕旋转的时候,Activity会销毁重建,如果我们想恢复之前的数据,之前一般是通过onSaveInstanceState()
来实现,内部是通过Bundle来实现,此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,而ViewModel
可以很简单的实现这个功能,并存储较大的数据;
源码分析
ViewModel是如何创建的?
val viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
以上是ViewModel
创建代码
ViewModelProvider(this)做了什么?
### ViewModelProvider.javapublic ViewModelProvider(@NonNull ViewModelStoreOwner owner) {this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory(): NewInstanceFactory.getInstance());}
ComponentActivity
则实现了ViewModelStoreOwner
和HasDefaultViewModelProviderFactory
接口;
因此我们只需要关注ComponentActivity
中对应的方法;
getViewModelStore()
;getDefaultViewModelProviderFactory()
;
我们先分析getViewModelStore:
### ComponentActivity.getViewModelStorepublic ViewModelStore getViewModelStore() {...ensureViewModelStore();return mViewModelStore;}
可以看到getViewModelStore()
调用了ensureViewModelStore()
,其对应代码如下:
### ComponentActivity.ensureViewModelStorevoid ensureViewModelStore() {if (mViewModelStore == null) {NonConfigurationInstances nc =(NonConfigurationInstances) getLastNonConfigurationInstance();if (nc != null) {// Restore the ViewModelStore from NonConfigurationInstancesmViewModelStore = nc.viewModelStore;}if (mViewModelStore == null) {mViewModelStore = new ViewModelStore();}}}static final class NonConfigurationInstances {Object custom;ViewModelStore viewModelStore;}
在ensureViewModelStore
方法中,会判断mViewModelStore
是否为null,如果为null的话,会先尝试调用getLastNonConfigurationInstance()
方法获取,如果获取不到,则直接new创建一个ViewModelStore
;
我们看下ViewModelStore
类:
public class ViewModelStore {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();}
}
其内部创建了一个HashMap
,以ViewModel的CanonicalName
为key,ViewModel
对象为value,存储Activity中创建的ViewModel对象;
我们再看下getDefaultViewModelProviderFactory()
方法:
### ComponentActivity.getDefaultViewModelProviderFactory()public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {...if (mDefaultFactory == null) {mDefaultFactory = new SavedStateViewModelFactory(getApplication(),this,getIntent() != null ? getIntent().getExtras() : null);}return mDefaultFactory;}
主要是创建一个SavedStateViewModelFactory
对象返回,我们看下SavedStateViewModelFactory的构造方法
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();}
我们看下mFactory
的创建,application
肯定不为null,因此会调用ViewModelProvider.AndroidViewModelFactory.getInstance(application)返回一个AndroidViewModelFactory对象
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {private static AndroidViewModelFactory sInstance;public static AndroidViewModelFactory getInstance(@NonNull Application application) {if (sInstance == null) {sInstance = new AndroidViewModelFactory(application);}return sInstance;}private Application mApplication;public AndroidViewModelFactory(@NonNull Application application) {mApplication = application;}@NonNull@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {if (AndroidViewModel.class.isAssignableFrom(modelClass)) {try {return modelClass.getConstructor(Application.class).newInstance(mApplication);} catch (NoSuchMethodException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);} catch (IllegalAccessException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);} catch (InstantiationException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);} catch (InvocationTargetException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);}}return super.create(modelClass);}}
可以看到AndroidViewModelFactory
主要是用来生产ViewModel的
,其create()
方法:根据传入的ViewModel
类型【继承自AndroidViewModel或ViewModel】,通过反射创建ViewModel对象;
小结
调用ViewModelProvider(this)
方法主要做了以下两件事:
-
获取
ViewModelStore
对象,如果ViewModelStore
为null,会先尝试调用getLastNonConfigurationInstance()
方法获取,获取不到则直接通过new创建,内部通过HashMap
实现ViewModel
对象的存储; -
创建
AndroidViewModelFactory
对象,其内部提供了create()
,使用反射创建对应的ViewModel
对象;
get(MyViewModel::class.java)做了什么?
### ViewModelProvider.javapublic <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@MainThreadpublic <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;}
小结
get(MyViewModel::class.java)方法
会根据传入的ViewModel的CanonicalName
,先从mViewModelStore
缓存中查找,如果找到,则直接返回,如果没找到,则调用前面创建的mFactory.create()
方法通过反射创建对应的ViewModel
,并添加到 mViewModelStore
缓存中;
以上便是ViewModel
相关的创建逻辑源码分析!
ViewModel是如何实现配置更改后数据恢复的?
我们知道当屏幕旋转配置发生变化时,会调用onDestroy()
,在ComponentActivity构造方法中:
getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {if (event == Lifecycle.Event.ON_DESTROY) {// Clear out the available contextmContextAwareHelper.clearAvailableContext();// And clear the ViewModelStoreif (!isChangingConfigurations()) {getViewModelStore().clear();}}}});
当监听到Activity
调用ON_DESTROY
时,会调用getViewModelStore().clear()
,清除ViewModelStore
内部缓存的ViewModel
对象,那为何重新创建后,ViewModel
中持有的数据又没有丢失呢?
当Activity
销毁时会调用ActivityThread.handleDestroyActivity()
方法:
public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,boolean getNonConfigInstance, String reason) {ActivityClientRecord r = performDestroyActivity(token, finishing,configChanges, getNonConfigInstance, reason);if (r != null) {...}mSomeActivitiesChanged = true;}
handleDestroyActivity方法中又会调用performDestroyActivity()方法:
ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,int configChanges, boolean getNonConfigInstance, String reason) {...ActivityClientRecord r = mActivities.get(token);if (getNonConfigInstance) {try {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);}}}...return r;}
performDestroyActivity方法中会调用activity.retainNonConfigurationInstances()
NonConfigurationInstances retainNonConfigurationInstances() {Object activity = onRetainNonConfigurationInstance();...return nci;}
retainNonConfigurationInstances()
方法中又调用onRetainNonConfigurationInstance()
,其在ComponentActivity
中具体实现代码如下:
public final Object onRetainNonConfigurationInstance() {Object custom = onRetainCustomNonConfigurationInstance();ViewModelStore viewModelStore = mViewModelStore;if (viewModelStore == null) {NonConfigurationInstances nc =(NonConfigurationInstances) getLastNonConfigurationInstance();if (nc != null) {viewModelStore = nc.viewModelStore;}}if (viewModelStore == null && custom == null) {return null;}NonConfigurationInstances nci = new NonConfigurationInstances();nci.custom = custom;nci.viewModelStore = viewModelStore;return nci;}
可以看到会将viewModelStore
保存到NonConfigurationInstances
对象里返回,结合performDestroyActivity源码
,最终会保存到ActivityClientRecord.lastNonConfigurationInstances属性
中;
当Activity
重新创建的时候,会执行ActivityThread.performLaunchActivity()
方法:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {...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);...return activity;}
会调用 activity.attach()
方法将lastNonConfigurationInstances
对象传入,并赋值给Activity中的mLastNonConfigurationInstances属性
;同时在ComponentActivity的构造方法中找到如下代码:
getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {ensureViewModelStore();getLifecycle().removeObserver(this);}});
而ensureViewModelStore()
方法上面我们已经看到,内部会先调用getLastNonConfigurationInstance()
方法获取mViewModelStore
对象,getLastNonConfigurationInstance()
方法返回的正是mLastNonConfigurationInstances
属性;从而实现ViewModel
数据的恢复!
整体时序图
结语
如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )