1,关于上一节简单使用我自己发出的疑问
1),counterViewModel=new ViewModelProvider(this).get(CounterViewModel.class);一句话实例化viewmodel,google很贴心,但究竟里面做了什么?
2),为什么在屏幕选转重走activity生命周期时候,counterViewModel数据不受影响,counterViewModel到底有没有重新被实例化,数据是怎么维持不变的
3),onCleared()方法在activity被销毁时自动调用是怎么实现的?
2走进代码
问题一:new ViewModelProvider(this).get(CounterViewModel.class)做了啥事
这句代码做了什么
counterViewModel=new ViewModelProvider(this).get(CounterViewModel.class);
我们先看看ViewModelProvider(this)的代码
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
ViewModelProvider的构造函数要求接收ViewModelStoreOwner作为参数,ViewModelStoreOwner是一个接口类
public interface ViewModelStoreOwner {
@NonNull
ViewModelStore getViewModelStore();
}
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();
}
}
看到这里基本可以做出三个猜测
a),ViewModelStore里面维护一个HashMap存储viewmodel类型数据,我们自己编写继承viewmodel的实例可能缓存在ViewModelStore这里
b),可能有个实现ViewModelStoreOwner接口的缓存集合类可以直接getViewModelStore
c),activity的父类必定实现了ViewModelStoreOwner 接口
d),实现了ViewModelStoreOwner的acitivity父类,肯定可以获取到ViewModel并进行相关操作
关于问题d,在ComponentActivity中找到了
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner {
我们继续看看ComponentActivity实现了这个接口后做了什么
@NonNull
@Override
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
//从NonConfigurationInstances中恢复ViewModelStore
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
如果mViewModelStore不为空直接返回,要是为空在NonConfigurationInstances不为空的情况下,由NonConfigurationInstances恢复,再不然就直接new了
先看看NonConfigurationInstances类
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
里面维护着一个ViewModelStore,且是fianl修饰class,典型的单例模式,这就能解释为何可以直接恢复ViewModelStore了,在看看getLastNonConfigurationInstance()的具体实现
***在Activity基类下***
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
static final class NonConfigurationInstances {
Object activity;
HashMap<String, Object> children;
FragmentManagerNonConfig fragments;
ArrayMap<String, LoaderManager> loaders;
VoiceInteractor voiceInteractor;
}
@UnsupportedAppUsage
/* package */ NonConfigurationInstances mLastNonConfigurationInstances;
很明显这里是缓存activity,fragment还有其他几个暂时不知道用处的对象, ViewModelStore getViewModelStore()只获取了mLastNonConfigurationInstances.activity信息,
其实这里可以划重点了:
getLastNonConfigurationInstance()这里可以恢复activity保存的最新数据,当然包括viewModelStore
再看看 ViewModelProvider(this).get(CounterViewModel.class);中的get(CounterViewModel.class)方法
@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);
}
具体操作在下面的get()里面
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 {
//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);
return (T) viewModel;
}
这段代码也不难理解,如果存在modelClass实例,那就直接返回;否则就创建一个,这里看到了2个mFactory类,OnRequeryFactory类型和KeyedFactory类型,其实KeyedFactory也是继承OnRequeryFactory,但是这两个都实现了Factory 接口
public interface Factory {
@NonNull
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
Factory有2个实现类,分别是NewInstanceFactory和AndroidViewModelFactory ;NewInstanceFactory传入context会引起内存泄漏
回顾下面这段代码
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}

ComponentActivity实现了HasDefaultViewModelProviderFactory这个接口
具体的实现内容是
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mDefaultFactory == null) {
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this,
getIntent() != null ? getIntent().getExtras() : null);
}
return mDefaultFactory;
}
*************************************************************************************************************
@SuppressLint("LambdaLast")
public SavedStateViewModelFactory(@NonNull Application application,
@NonNull SavedStateRegistryOwner owner,
@Nullable Bundle defaultArgs) {
mSavedStateRegistry = owner.getSavedStateRegistry();
mLifecycle = owner.getLifecycle();
mDefaultArgs = defaultArgs;
mApplication = application;
mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
代码最终还是用AndroidViewModelFactory传入application作为context
最后,
public AndroidViewModelFactory(@NonNull Application application) {
mApplication = application;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
//到头来还是用反射
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch (Exception e) {
//省略了很多异常抛出
}
}
return super.create(modelClass);
}
到这里基本可以说明这简单的一句话做了哪些工作了
counterViewModel=new ViewModelProvider(this).get(CounterViewModel.class);
总结:activity的父类实现了ViewModelStoreOwner接口,在具体的实现中维护者一个ViewModelStore对象,缓存着我们自定义Viewmodel的子类,在调用new ViewModelProvider(this)的时候,首先判断activity实现的是NewInstanceFactory还是AndroidViewModelFactory的接口,然后到对应的工厂方法里面查看缓存是否存在实例,有则返回;没有就反射创建一个;
问题二:为什么在屏幕选转重走activity生命周期时候,ViewModel数据不受影
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
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;
}
上个问题说可以通过NonConfigurationInstances恢复viewModelStore,细看最后几句,NonConfigurationInstances也是再次在这里保存了viewModelStore数据,所以onRetainNonConfigurationInstance() 方法保存了viewModelStore数据;
上个问题也说了getLastNonConfigurationInstance();可以获取到activity保存的最新viewmodelStore数据
可以这样总结:
在旋转屏幕重走屏幕生命周期时,通过getLastNonConfigurationInstance()获取viewModelStore数据,再而从hashmap中取出我们自定义的缓存实例,从而获取到原来的操作状态
所以Android除了onSaveInstanceState()和onRestoreInstanceState()之外,还有onRetainNonConfigurationInstance()和etLastNonConfigurationInstance()这对兄弟,而且这对兄弟存储的信息量可以很大,不受限制
查看资料后发现还有一对姐妹saveManagedDialogs()和restoreManagedDialogs()不过这是应用于对话框的;
问题三:onCleared()方法在activity被销毁时自动调用是怎么实现的?

很明显ComponentActivity通过lifecycle管理生命周期并在ON_DESTROY回调时执行 getViewModelStore().clear();具体操作是遍历hashmap,之心viewModel.clear();
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
网友评论