前言
本文主要分析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.java
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
ComponentActivity
则实现了ViewModelStoreOwner
和HasDefaultViewModelProviderFactory
接口;
因此我们只需要关注ComponentActivity
中对应的方法;
-
getViewModelStore()
; -
getDefaultViewModelProviderFactory()
;
我们先分析getViewModelStore:
### ComponentActivity.getViewModelStore
public ViewModelStore getViewModelStore() {
...
ensureViewModelStore();
return mViewModelStore;
}
可以看到getViewModelStore()
调用了ensureViewModelStore()
,其对应代码如下:
### ComponentActivity.ensureViewModelStore
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = 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
@Override
public <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.java
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;
}
小结
get(MyViewModel::class.java)方法
会根据传入的ViewModel的CanonicalName
,先从mViewModelStore
缓存中查找,如果找到,则直接返回,如果没找到,则调用前面创建的mFactory.create()
方法通过反射创建对应的ViewModel
,并添加到 mViewModelStore
缓存中;
以上便是ViewModel
相关的创建逻辑源码分析!
ViewModel是如何实现配置更改后数据恢复的?
我们知道当屏幕旋转配置发生变化时,会调用onDestroy()
,在ComponentActivity构造方法中:
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()) {
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() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
ensureViewModelStore();
getLifecycle().removeObserver(this);
}
});
而ensureViewModelStore()
方法上面我们已经看到,内部会先调用getLastNonConfigurationInstance()
方法获取mViewModelStore
对象,getLastNonConfigurationInstance()
方法返回的正是mLastNonConfigurationInstances
属性;从而实现ViewModel
数据的恢复!
整体时序图
文章来源:https://www.toymoban.com/news/detail-512660.html
结语
如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )文章来源地址https://www.toymoban.com/news/detail-512660.html
到了这里,关于Android JetPack 深入分析ViewModel源码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!