首先如果我们想要多个不同的 fragment 中拿到同一份的 ViewModel 我们比较常规的用法如下:
ViewModelProviders.of(this@activity).get(TempViewModel::class.java)
如上代码所示,在 fragment 中获取ViewModel传入同一个 Activity,就能拿到同一个对应类型的 ViewModel对象。
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
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 {
//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;
}
首先通过静态的 of() 方法我们可以看到,实际上创建的时候传入的一个 ViewModelStore、 factory 创建出 ViewModelProvider。 然后调用 get()方法来获取对应类型的 ViewModel。
在 get()方法中,会根据传入的 key(可以自定义)去判断 ViewModelStore 中是否有已经创建的 ViewModel,有的话直接返回,没有的话,会根据前面传入的(默认创建的或是传进来) factory 去创建指定ViewModel,然后存到这个 ViewModelStore中,并且返回 ViewModel。
ViewModelStore 是什么?简单的理解,那就是用于存储 ViewModel,原理也很简单,内部维护一个 HashMap
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();
}
}
通过上面代码我们就可以看到,只要传入的 ViewModelStore 相同,对应的 key 相同,我们就可以拿到同一个。
所以通过上面的知识,我们可以知道,只要多个 activity 在获取 ViewModel 时传入同一个 ViewModelStore、同一个 ViewModel Class就可以从对应的 ViewModelStore 中获取到同一份ViewModel了。这样一来就可以实现在跨不同生命周期对象来共享同一份ViewModel。但是需要注意的是,需要考虑传入的 ViewModelStore 的生命周期。
除此之外,我们还可以通过传入不同的Key,来获取不同实例的同类型ViewModel,具体可阅读ViewModel源码,已经有现成的API提供给我们使用。