通常我们在Activity/Fragment中创建ViewModel使用如下方式:
NameViewModel nameViewModel=new ViewModelProvider(this).get(NameViewModel.class);
其中ViewModelStore对象由Activity/Fragment提供,并且在Activity/Fragment销毁时调用ViewModel的clear方法
那Activity、Fragment如何创建ViewModelStore的呢?让我我们一起来看看源码,解开疑惑
与Activity关联的ViewModelStore对象
ViewModelStore 用于存储ViewModel实例对象,在androidx.activity.ComponentActivity中实现了ViewModelStoreOwner接口,
实现代码如下:
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
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
第13行获取上一次的对象,Android系统提供的一种机制,在系统配置(如屏幕有竖屏变为横屏时)改变时,Activity将会重新创建,通过覆盖onRetainNonConfigurationInstance,将viewModelStore返回,确保ViewModelStore不会从新创建,以此保证与该ViewModelStore关联的ViewModel不因配置改变而丢失,onRetainNonConfigurationInstance代码如下
@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;
}
从上面的源码分析可知,只要利用相同的Activity实例调用ViewModelProvider(thisAcitivty).get(viewModelClass) 创建的将会是同一个对象,在该Activity关联的Fragment中也一样。
与androidx.fragment.app.Fragment关联的ViewModelStore对象
同样androidx.fragment.app.Fragment也实现了ViewModelStoreOwner接口
源码如下:
public ViewModelStore getViewModelStore() {
if (mFragmentManager == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
return mFragmentManager.getViewModelStore(this);
}
可以看出ViewModelStore的获取委托给了FragmentManager实现
继续看 FragmentManager getViewModelStore 的方法
private FragmentManagerViewModel mNonConfig;
....省略无关代码
ViewModelStore getViewModelStore(@NonNull Fragment f) {
return mNonConfig.getViewModelStore(f);
}
在FragmentManager中通过mNonConfig获取ViewModelStore对象,看看mNonConfig如果创建的:
void attachController(@NonNull FragmentHostCallback<?> host,
@NonNull FragmentContainer container, @Nullable final Fragment parent) {
if (mHost != null) throw new IllegalStateException("Already attached");
mHost = host;
mContainer = container;
mParent = parent;
...省略无关代码
// Get the FragmentManagerViewModel
if (parent != null) {
mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
} else if (host instanceof ViewModelStoreOwner) {
ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
} else {
mNonConfig = new FragmentManagerViewModel(false);
}
}
这里在创建mNonConfig时有三种情形:
第一种:当parent!=null说明是在Fragment中又启动的Fragment,调用父Fragment的FragmentManager.getChildNonConfig()创建FragmentManagerViewModel,实际是到查找父Fragment关联的FragmentManagerViewModel 的HashMap中是否有子Fragment的FragmentManagerViewModel,没有就创建,并缓存到mChildNonConfigs中
第二种:当host实现了ViewModelStoreOwner接口,这中情况大多数是在Activity中启动了Fragment,host就是Activity,host.getViewModelStore()获取的即是Activity的ViewModelStore。通过FragmentManagerViewModel.getInstance(viewModelStore)创建FragmentManagerViewModel,实际是利用Activity的ViewModelProvider创建,通过分析我们能构发现,创建的FragmentManagerViewModel也在Activity的ViewModelStore中。这样在Activity/Fragment销毁时FragmentManagerViewModel 会跟着Activity/fragment的销毁
第三中:如果非以上两种就直接创建实例并且不保存FragmentManagerViewModel的状态,通常不会到这个分支
FragmentManagerViewModel 数据结构
final class FragmentManagerViewModel extends ViewModel {
private static final ViewModelProvider.Factory FACTORY = new ViewModelProvider.Factory() {
@NonNull
@Override
@SuppressWarnings("unchecked")
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
FragmentManagerViewModel viewModel = new FragmentManagerViewModel(true);
return (T) viewModel;
}
};
@NonNull
static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
ViewModelProvider viewModelProvider = new ViewModelProvider(viewModelStore,
FACTORY);
return viewModelProvider.get(FragmentManagerViewModel.class);
}
...省略无关代码
private final HashMap<String, Fragment> mRetainedFragments = new HashMap<>();
private final HashMap<String, FragmentManagerViewModel> mChildNonConfigs = new HashMap<>();
private final HashMap<String, ViewModelStore> mViewModelStores = new HashMap<>();
...省略无关代码
@NonNull
FragmentManagerViewModel getChildNonConfig(@NonNull Fragment f) {
FragmentManagerViewModel childNonConfig = mChildNonConfigs.get(f.mWho);
if (childNonConfig == null) {
childNonConfig = new FragmentManagerViewModel(mStateAutomaticallySaved);
mChildNonConfigs.put(f.mWho, childNonConfig);
}
return childNonConfig;
}
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
if (viewModelStore == null) {
viewModelStore = new ViewModelStore();
mViewModelStores.put(f.mWho, viewModelStore);
}
return viewModelStore;
}
}
总结
- ViewModel通过Activity/Fragment提供的ViewModelStore将ViewModel的生命周期跟Activity/Fragment关联起来(ViewModel 的生命周期非常简单就是onCleared方法)。
- ViewModel具有生命范围,Activity范围和Fragment范围