ViewModel是android架构组件中非常重要的一个组件,它是Android架构分层的核心,有关它的用法和资料可以参考
Android架构组件一 Android Architecture Components开发入门
也可以参考官方给出的示例https://developer.android.google.cn/topic/libraries/architecture/viewmodel.html
接下来我们从以下几个方面介绍ViewModel组件
ViewModel组件的官方定义如下:
The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.
翻译过来就是ViewModel是存储和管理lifecycle 重新创建的数据的组件,在lifecycle 在配置改变或者屏幕旋转时数据仍然在生存周期内。另外ViewModel还可以用来负责UI组件间的通信,它是解耦Activity/Fragment View层的关键。
ViewModel在Android架构组件中的位置如下:
可以看到ViewModel处于Activity(View)和Repository(Model)层之间,它类似于MVP中的P层,向下对View层提供操作Model层的接口,向上使用观察者模式观察Model层,当Model层感兴趣的数据发生变化时通知View层,当然这个是ViewModel中引用的LiveData组件来实现的,这个将会在下面一篇博文中来讲解。
ViewModel组件有非常大的一个意义就是它的实例不会因为Activity/Fragment因为配置发生改变或者屏幕旋转时重新创建ViewModel对象。这个是ViewModel区别与MVP中P的基本特点之一。官方给出了如下的图示说明ViewModel的生命周期。
可以看到,只有当Activity的finish()方法被调用时,ViewModel.onCleared()方法会被调用,对象才会被销毁。这张图很好的描述了是当Activity被recreate时,ViewModel的生命周期。关于这一点是如何做到的,参考下面的讲解。
注意:*在ViewModel中不要持有Activity等View层的引用,如果需要引用Context,请使用AndroidViewModel,它引用了Application Context*
官方说明如下:
Caution: A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity context
查看Android架构组件的源码,我们可以得到如下的UML类图。
这里有几个比较重要的类
ViewModelProviders:创建ViewModelProvider的工具类,提供以下四个方法创建ViewModelProvider
public static ViewModelProvider of(@NonNull Fragment fragment)
public static ViewModelProvider of(@NonNull FragmentActivity activity)
public static ViewModelProvider of(@NonNull Fragment fragment, @NonNull Factory factory)
public static ViewModelProvider of(@NonNull FragmentActivity activity,@NonNull Factory factory)
创建时可以指定创建的Factory ,默认已经有一个Factory,定义如下:
public static class DefaultFactory extends ViewModelProvider.NewInstanceFactory {
private Application mApplication;
/**
* Creates a {@code DefaultFactory}
*
* @param application an application to pass in {@link AndroidViewModel}
*/
public DefaultFactory(@NonNull Application application) {
mApplication = application;
}
@NonNull
@Override
public T create(@NonNull Class modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
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);
}
}
重写了public < T extends ViewModel > T create(@NonNull Class < T > modelClass)创建ViewModel对象。
ViewModelProvider: 真正创建和存储ViewModel的类,将创建的ViewModel保存在ViewModelStore 对象mViewModelStore中
创建逻辑如下:
@NonNull
@MainThread
public T get(@NonNull String key, @NonNull Class modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
ViewModelStores:创建ViewModelStore的工具类,关联着HoldFragment ,并返回HolderFragment中的ViewModelStore对象
ViewModelStore: 保存和管理ViewModel的类,里面引用一个HashMap来保存ViewModel对象。并在HolderFragment销毁时清理掉所保存的ViewModel对象。
public class ViewModelStore {
private final HashMap mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.get(key);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
mMap.put(key, viewModel);
}
final ViewModel get(String key) {
return mMap.get(key);
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
HolderFragment:继承自Fragment,是ViewModel在配置改变不被销毁的秘密所在,它主要为ViewModelProvider创建ViewModel提供所需要的ViewModelStore。
在ViewModelStores中有如下关键代码:
public static ViewModelStore of(@NonNull FragmentActivity activity) {
return holderFragmentFor(activity).getViewModelStore();
}
这里的holderFragmentFor就是HolderFragment中的方法,定义如下:
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
return sHolderFragmentManager.holderFragmentFor(activity);
}
....
HolderFragment holderFragmentFor(FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
HolderFragment holder = findHolderFragment(fm);
if (holder != null) {
return holder;
}
holder = mNotCommittedActivityHolders.get(activity);
if (holder != null) {
return holder;
}
if (!mActivityCallbacksIsAdded) {
mActivityCallbacksIsAdded = true;
activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
}
holder = createHolderFragment(fm);
mNotCommittedActivityHolders.put(activity, holder);
return holder;
}
有关这些类的详细实现请参考源码。
1 ViewModel实例的创建过程
ViewModel实例的创建过程比较复杂,先经过ViewModelProviders类,再经过ViewModelStores,在跳转到HolderFragment得到ViewModelStore对象,最终跳转到ViewModelProvider的public < T extends ViewModel > T get(@NonNull String key, @NonNull Class< T> modelClass)方法中创建的。整个流程如下:
因此,这里我们最终来看ViewModelProvider的public < T extends ViewModel > T get(@NonNull String key, @NonNull Class< T> modelClass)方法
@NonNull
@MainThread
public T get(@NonNull String key, @NonNull Class modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
主要做了以下几件事情
(1) 从mViewModelStore中获取ViewModel对象,mViewModelStore是一个ViewModelStore对象,在创建ViewModelProvider传递过来的,第一次肯定获取为NULL。
(2) 判断是否是ViewModel的实例对象,如果是直接返回,当获取的不为NULL时,且传递的Class对象正确,就就可以在这里直接返回了,说明VikewModel对象之前创立过
(3) 调用mFactory的< T extends ViewModel > T create(@NonNull Class< T> modelClass)创建一个ViewModel对象,mFactory由创建ViewModelProvider指定,一般通过反射创建该对象。例如默认的DefaultFactory对象。
(4) 创建好ViewModel对象后将该对象缓存起来,保存到mViewModelStore中并返回ViewModel对象。
这样,整个ViewModel创建的过程就结束了。还是借用一下别人的序列图。
2 ViewModel实例为什么不会因为Activity 重新创建而销毁?
这个问题很有意思,从一开始接触到ViewModel官方的说明我就很好奇,这个是如何实现的呢?我们知道,在Activity/Fragment 因为屏幕旋转,配置改变时,里面所引用的对象都会被重建,典型的是对话框,为此我们不得不在Activity的onSaveInstanceState()保存一些数据,然后在onCreate()中恢复数据。然而ViewModel却不需要,那么ViewModel是如何做到的呢?我们查看ViewModelProviders的源码发现每次的of()方法又都是创建一个新的ViewModelProvider对象的,这就更加疑惑了。
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
initializeFactoryIfNeeded(checkApplication(activity));
return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory);
}
答案是有两个关键点:
(1) HolderFragment在Activity/Fragment 被 re-create 的生命周期
(2) ViewModelProvider 中 mViewModelStore对象
这里分别依次来说明这两个关键点
(1) HolderFragment在Activity/Fragment 被 re-create 的生命周期
仔细阅读HolderFragment的源码,我们发现在构造方法中有这么一句
public HolderFragment() {
setRetainInstance(true);
}
很不起眼,却非常重要。
setRetainInstance(true);表明Fragment 不会因为Activity/Fragment 因为配置改变,屏幕旋转被销毁时,他会驻留在系统中,知道Activity/Fragment 被重新创建,然后onAttach上继续使用,也就是说HolderFragment在Activity/Fragment 因为配置改变,屏幕旋转被销毁时,不会走onDestory() –> onCreate()方法。这样保证了Activity/Fragment重新创建时还是之前那个HolderFragment对象,当然了里面的mViewModelStore也不会变。
(2) ViewModelProvider 中 mViewModelStore对象
由前面的分析得到Activity/Fragment重新创建时HolderFragment不会被重新创建,那么自然ViewModelStores中返回的ViewModelStore还是之前的ViewModelStore
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
return holderFragmentFor(activity).getViewModelStore();
}
这样子导致在创建ViewModelProvider传进去的ViewModelStore 对象还是Activity/Fragment之前的ViewModelStore 对象
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
this.mViewModelStore = store;
}
这样即使new 再多的ViewModelProvider实例,它里面的mViewModelStore 对象并没有被重新创建。这样在调用get(@NonNull String key, @NonNull Class < T> modelClass)方法时,将会在步骤(2)中返回,返回的ViewModel对象就是Activity/Fragment重新创建之前的那个ViewModel对象。
通过(1)(2)就保证了ViewModel实例不会因为Activity 重新创建而销毁。
3 HoldFragment解析
在ViewModel组件中定义了一个HoldFragment类,该类继承Fragment,但是里面没有任何布局文件,它最主要的作用就是来生成在Activity/Fragment重新创建时保证返回的ViewModelStore对象不会改变。为此它的实现如下:
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class HolderFragment extends Fragment {
private static final String LOG_TAG = "ViewModelStores";
private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final String HOLDER_TAG =
"android.arch.lifecycle.state.StateProviderHolderFragment";
private ViewModelStore mViewModelStore = new ViewModelStore();
public HolderFragment() {
setRetainInstance(true);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sHolderFragmentManager.holderFragmentCreated(this);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
public void onDestroy() {
super.onDestroy();
mViewModelStore.clear();
}
public ViewModelStore getViewModelStore() {
return mViewModelStore;
}
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
return sHolderFragmentManager.holderFragmentFor(activity);
}
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(Fragment fragment) {
return sHolderFragmentManager.holderFragmentFor(fragment);
}
@SuppressWarnings("WeakerAccess")
static class HolderFragmentManager {
private Map mNotCommittedActivityHolders = new HashMap<>();
private Map mNotCommittedFragmentHolders = new HashMap<>();
private ActivityLifecycleCallbacks mActivityCallbacks =
new EmptyActivityLifecycleCallbacks() {
@Override
public void onActivityDestroyed(Activity activity) {
HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
if (fragment != null) {
Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
}
}
};
private boolean mActivityCallbacksIsAdded = false;
private FragmentLifecycleCallbacks mParentDestroyedCallback =
new FragmentLifecycleCallbacks() {
@Override
public void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) {
super.onFragmentDestroyed(fm, parentFragment);
HolderFragment fragment = mNotCommittedFragmentHolders.remove(
parentFragment);
if (fragment != null) {
Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment);
}
}
};
void holderFragmentCreated(Fragment holderFragment) {
Fragment parentFragment = holderFragment.getParentFragment();
if (parentFragment != null) {
mNotCommittedFragmentHolders.remove(parentFragment);
parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(
mParentDestroyedCallback);
} else {
mNotCommittedActivityHolders.remove(holderFragment.getActivity());
}
}
private static HolderFragment findHolderFragment(FragmentManager manager) {
if (manager.isDestroyed()) {
throw new IllegalStateException("Can't access ViewModels from onDestroy");
}
Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);
if (fragmentByTag != null && !(fragmentByTag instanceof HolderFragment)) {
throw new IllegalStateException("Unexpected "
+ "fragment instance was returned by HOLDER_TAG");
}
return (HolderFragment) fragmentByTag;
}
private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
HolderFragment holder = new HolderFragment();
fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
return holder;
}
HolderFragment holderFragmentFor(FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
HolderFragment holder = findHolderFragment(fm);
if (holder != null) {
return holder;
}
holder = mNotCommittedActivityHolders.get(activity);
if (holder != null) {
return holder;
}
if (!mActivityCallbacksIsAdded) {
mActivityCallbacksIsAdded = true;
activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
}
holder = createHolderFragment(fm);
mNotCommittedActivityHolders.put(activity, holder);
return holder;
}
HolderFragment holderFragmentFor(Fragment parentFragment) {
FragmentManager fm = parentFragment.getChildFragmentManager();
HolderFragment holder = findHolderFragment(fm);
if (holder != null) {
return holder;
}
holder = mNotCommittedFragmentHolders.get(parentFragment);
if (holder != null) {
return holder;
}
parentFragment.getFragmentManager()
.registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false);
holder = createHolderFragment(fm);
mNotCommittedFragmentHolders.put(parentFragment, holder);
return holder;
}
}
}
首先在构造方法中调用了setRetainInstance(true),这样子在Activity/Fragment 因为配置发生改变时重新创建时,就不会销毁该HolderFragment 的实例,这样子HolderFragment 在下次Activity/Fragment重新创建时,并不会回调onDestory(),onCreate()方法,关于这一点。可以打点确认。
HoldFragment将创建实例的方法交给了HolderFragmentManager这个内部类,这个内部类首先创建了两个Map来保存了还未Attach但将要Attach 到Activity/Fragment的HoldFragment实例,并且注册了Activity/Fragment 的生命周期回调。接着创建HolderFragment实例,然后添加到map中去。
HolderFragment holderFragmentFor(FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
HolderFragment holder = findHolderFragment(fm);
if (holder != null) {
return holder;
}
holder = mNotCommittedActivityHolders.get(activity);
if (holder != null) {
return holder;
}
if (!mActivityCallbacksIsAdded) {
mActivityCallbacksIsAdded = true;
activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
}
holder = createHolderFragment(fm);
mNotCommittedActivityHolders.put(activity, holder);
return holder;
}
最后在HolderFragment的onCreate() 移除Map中添加的HoldFragment实例。因为回调到onCreate()方法,就说明HoldFragment已经成功的Attach到相应的Activity/Fragment 上了,这个时候需要移除mNotCommittedActivityHolders中的HoldFragment实例。
最后,在Activity finish之后,HoldFragment 会调用onDestory()方法,在这里面会清理掉mViewModelStore 中的ViewModel。
至此,ViewModel组件的分析已经基本完毕,下一篇将分析Android架构组件中LiveData组件
参考:
https://developer.android.google.cn/topic/libraries/architecture/viewmodel.html
https://shymanzhu.com/2017/12/28/Android%E6%9E%B6%E6%9E%84%E7%BB%84%E4%BB%B6%EF%BC%88%E4%B8%89%EF%BC%89%E2%80%94%E2%80%94ViewModel/