1 前言

ViewModel是android架构组件中非常重要的一个组件,它是Android架构分层的核心,有关它的用法和资料可以参考
Android架构组件一 Android Architecture Components开发入门
也可以参考官方给出的示例https://developer.android.google.cn/topic/libraries/architecture/viewmodel.html
接下来我们从以下几个方面介绍ViewModel组件

2 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架构组件中的位置如下:
Android架构组件三 Android Architecture Components ViewModel组件解析_第1张图片
可以看到ViewModel处于Activity(View)和Repository(Model)层之间,它类似于MVP中的P层,向下对View层提供操作Model层的接口,向上使用观察者模式观察Model层,当Model层感兴趣的数据发生变化时通知View层,当然这个是ViewModel中引用的LiveData组件来实现的,这个将会在下面一篇博文中来讲解。
ViewModel组件有非常大的一个意义就是它的实例不会因为Activity/Fragment因为配置发生改变或者屏幕旋转时重新创建ViewModel对象。这个是ViewModel区别与MVP中P的基本特点之一。官方给出了如下的图示说明ViewModel的生命周期。
Android架构组件三 Android Architecture Components ViewModel组件解析_第2张图片
可以看到,只有当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

3 ViewModel UML类图

查看Android架构组件的源码,我们可以得到如下的UML类图。
Android架构组件三 Android Architecture Components ViewModel组件解析_第3张图片

这里有几个比较重要的类
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;        }

有关这些类的详细实现请参考源码。

4 ViewModel解析

1 ViewModel实例的创建过程
ViewModel实例的创建过程比较复杂,先经过ViewModelProviders类,再经过ViewModelStores,在跳转到HolderFragment得到ViewModelStore对象,最终跳转到ViewModelProvider的public < T extends ViewModel > T get(@NonNull String key, @NonNull Class< T> modelClass)方法中创建的。整个流程如下:
Android架构组件三 Android Architecture Components ViewModel组件解析_第4张图片
因此,这里我们最终来看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创建的过程就结束了。还是借用一下别人的序列图。
Android架构组件三 Android Architecture Components ViewModel组件解析_第5张图片

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/

更多相关文章

  1. Java语言程序设计(六)对话框应用实例及随机数的产生
  2. vscode是什么?vscode实例用法汇总
  3. Asp.Net Core如何安装?详解Asp.Net Core安装的实例教程
  4. 浅谈 下载实例 核心架构设计
  5. 分享一篇ASP.NET实现进度条的图文实例
  6. 有关经典实例的文章推荐10篇
  7. SignalR实现实时Web聊天的实例代码
  8. 详细介绍MvcPager分页控件使用的实例方法
  9. 右值引用如何使用?总结右值引用实例用法

随机推荐

  1. android 窗口背景透明方法
  2. Google操作系统是经典骗局?
  3. android ViewPager动态加载问题
  4. Android(安卓)开发学习手记(三):关于PullToR
  5. Android程序退出彻底关闭进程的方法
  6. Android(安卓)Handler 泄漏
  7. 手机rom的那些坑
  8. Android使用外部字体
  9. android 手机屏幕密度等级和屏幕逻辑尺寸
  10. TranslateAnimation动画