MainViewModel mainViewModel = new ViewModelProvider(this).get(MainViewModel.class);
MainViewModel mainViewModel = new ViewModelProvider(getActivity()).get(MainViewModel.class);
上面两行代码中,第一行的“this” 关键字,既可以指代Activity本身,也可以指代Fragment本身。上第二行的“getActivity()”,则只能是指代Fragment的宿主Activity。
因此,Fragment之间的通信,我们可以通过这个上面第二行的方式,通过要通信的几个Fragment及宿主Activity共同创建一个ViewModel对象,在ViewModel对象中实现跨Fragment+Activity通信。
创建一个ViewModel,为什么在Activity/Fragment意外销毁(如旋转屏幕,黑白夜模式切换,语音言换)后,重启,ViewModel还存在,且与之前一样,没发生变化?
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
// 在 Activity/Fragment中,实现的都是 ViewModelStoreOwner 接口,因此,在Activity/Fragment创建 ViewModel 对象时,
// 下面 this()方法的第二个参数 对应的三目运算,通常会执行 后面的部分:NewInstanceFactory.getInstance()。
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
最后调用到这里:
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
其中 mFactory 和 mViewModelStore定义如下:
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
Factory是一个接口,轻定义如下:
public interface Factory {
@NonNull
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
ViewModelStore 定义如下:
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
// 执行put方法时,会判断 传入的“key”是否存在对应的 ViewModel 对象,如果存在,则执行 onCleared()方法。
// 当然 ViewModel 的 onCleared()方法是一个空实现,具体的逻辑需要开发者自己去实现。
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
// 根据 传进来的key,获取对应的 ViewModel 对象。当 Activity/Fragment意外销毁时,ViewModelStore对象还是存在的,并没有随之销毁。
// 因此 Activity/Fragment 重建后,会调用该 get()方法重新获取到 ViewModel 对象。
final ViewModel get(String key) {
return mMap.get(key);
}
Set<String> keys() {
return new HashSet<>(mMap.keySet());
}
// 当 应用被销毁时,会调用 该方法,清空所有的 ViewModel 对象:
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
onCleared()方法实现如下:
protected void onCleared() {
}
ViewModel的 clear()方法实现如下:
@MainThread
final void clear() {
mCleared = true;
if (mBagOfTags != null) {
synchronized (mBagOfTags) {
for (Object value : mBagOfTags.values()) {
closeWithRuntimeException(value);
}
}
}
onCleared();
}
首先,我们要主要到该方法的注解:@MainThread,表明该方法只能是在主线程里面执行。
其次,mBagOfTags 定义如下:
@Nullable
private final Map<String, Object> mBagOfTags = new HashMap<>();
因此,mBagOfTags一定不为空,上面clear()方法的if(){...}判断会执行。 closeWithRuntimeException()方法实现如下:
private static void closeWithRuntimeException(Object obj) {
if (obj instanceof Closeable) {
try {
((Closeable) obj).close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
ViewModelStore的 clear()方法在 Activity的 onDestroy()方法中调用:
ComponentActivity.java中的调用如下:
public 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();
}
}
}
});
}
ViewModelStore的 clear()方法在Fragment中,并不是由Fragment本身调用的,而是由 FragmentManagerViewModel.java调用的:
void clearNonConfigState(@NonNull Fragment f) {
if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
Log.d(TAG, "Clearing non-config state for " + f);
}
// Clear and remove the Fragment's child non config state
FragmentManagerViewModel childNonConfig = mChildNonConfigs.get(f.mWho);
if (childNonConfig != null) {
childNonConfig.onCleared();
mChildNonConfigs.remove(f.mWho);
}
// Clear and remove the Fragment's ViewModelStore
ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
if (viewModelStore != null) {
viewModelStore.clear();
mViewModelStores.remove(f.mWho);
}
}
或者在Jetpack组件中的 navigation 组件的 NavControllerViewModel.java 调用(NavControllerViewModel继承了ViewModel):
private final HashMap<UUID, ViewModelStore> mViewModelStores = new HashMap<>();
void clear(@NonNull UUID backStackEntryUUID) {
// Clear and remove the NavGraph's ViewModelStore
ViewModelStore viewModelStore = mViewModelStores.remove(backStackEntryUUID);
if (viewModelStore != null) {
viewModelStore.clear();
}
}
@Override
protected void onCleared() {
for (ViewModelStore store: mViewModelStores.values()) {
store.clear();
}
mViewModelStores.clear();
}
mViewModelStores变量保存ViewModelStore对象的put()方法:
@NonNull
ViewModelStore getViewModelStore(@NonNull UUID backStackEntryUUID) {
ViewModelStore viewModelStore = mViewModelStores.get(backStackEntryUUID);
if (viewModelStore == null) {
viewModelStore = new ViewModelStore();
mViewModelStores.put(backStackEntryUUID, viewModelStore);
}
return viewModelStore;
}
该方法既执行了 mViewModelStores 的get()方法,也执行了 mViewModelStores 的put()方法。 ViewModelStore分析完,我们在回到 Factory 接口,在这里,他一共有两个 实现类:
抽象类 KeyedFactory 如下:
abstract static class KeyedFactory extends OnRequeryFactory implements Factory {
@NonNull
public abstract <T extends ViewModel> T create(@NonNull String key,
@NonNull Class<T> modelClass);
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
throw new UnsupportedOperationException("create(String, Class<?>) must "
+ "be called on implementaions of KeyedFactory");
}
}
实体类 NewInstanceFactory 如下:
public static class NewInstanceFactory implements Factory {
private static NewInstanceFactory sInstance;
// 该方法在 ViewModelProvider 的构造方法中被引用到,创建一个 NewInstanceFactory 对象
@NonNull
static NewInstanceFactory getInstance() {
if (sInstance == null) {
sInstance = new NewInstanceFactory();
}
return sInstance;
}
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
try {
return modelClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
}
这两个 Factory 的子类,关键的都是 各自的create()方法,后面我还还会提到。
上面是 我们在创建 MainViewModel 对象时,第一步操作“new ViewModelProvider(this)”所看到的。
然后是 new ViewModelProvider(this).get(MainViewModel.class)后面的get()方法,他的实现如下:
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
// Class.getCanonicalName()返回的是 该类的 package包名 + 类名。不是全限定名。
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
静态变量 DEFAULT_KEY定义如下:
private static final String DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey";
因此,某个指定的 ViewModel所对应的key值“DEFAULT_KEY + ":" + canonicalName”,永远是不变的,相当于是final类型的。
然后get()方法调用到:
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
// 从上面分析过的 mViewModelStore 对象中 的 mMap 变量中获取 key 值对应的 ViewModel对象
ViewModel viewModel = mViewModelStore.get(key);
// 如果我们传进来的 ViewModel 类与这里获取到的 ViewModel对象的类是同一个,就表明 我们所要创建 ViewModel的对象已经存在了会直接返回;
// 因此,当我们反复的调用 ViewModelProvider 去创建 ViewModel的对象 时,系统只会创建一次,之后世界从 mMap 中去获取,容纳后return返回。
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.
}
}
// 如果我们在初始化 ViewModelProvider 时,传进来的 Factory 对象是 KeyedFactory 类型的,
// 那么久调用 KeyedFactory的 create()方法去创建一个 ViewModel 对象,并保存到 mMap中。
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
// 如果我们在初始化 ViewModelProvider 时,传进来的 Factory 对象是 NewInstanceFactory 类型的,
// 就调用 NewInstanceFactory 的 create()方法去创建一个 ViewModel 对象,并保存到 mMap中。
} else {
viewModel = mFactory.create(modelClass);
}
// 最后是调用 put()方法,将创建的 ViewModel 对象保存到 mViewModelStore 对象中 的 mMap 变量中
mViewModelStore.put(key, viewModel);
return (T) viewModel; // 返回创建的 ViewModel 对象。
}
NewInstanceFactory的create()方法如下:
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
try {
// 其实就是通过反射创建对象。没什么可多说的。
return modelClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
在比较靠前的地方,我提到过,ViewModelProvider的构造方法里面的三目运算,执行的是后面的一个:
NewInstanceFactory.getInstance()
因此,上面的get()方法中,mFactory 是 NewInstanceFactory 类型的,不是 KeyedFactory 类型的,因此,get()方法的if判断:
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
} else {
viewModel = mFactory.create(modelClass);
}
会执行 else { ...... } 分支,在 NewInstanceFactory 的 create()方法 中,通过反射的形式,创建ViewModel对象。
然后执行:
mViewModelStore.put(key, viewModel);
将创建的 ViewModel对象 保存到 ViewModelStore 里面的 mMap中。
就这样,即便当Activity/Fragment因意外而销毁时,ViewModelStore中保存的对应的 Activity/Fragment的ViewModel对象还在,因此,Activity/Fragment重建时,执行onCreate()方法时,就能直接获取到 ViewModel对象,并从中读取到数据,恢复状态。