ViewModel
是google官方的MVVM架构组件,目前已经集成到了最新的支持库中了,是MVVM架构的核心组件之一。不懂MVVM的请看之前的文章:(一)Android官方MVVM框架实现组件化之整体结构
网上看到的ViewModel的博文千篇一律,实在忍不了,自己写看了源码写了一篇,欢迎拍砖!
ViewModel是存储UI相关数据并不会因为旋转而销毁的类。
最为重要的就是ViewModel具有下面的生命周期,这就是ViewModel的最可贵之处:
正因为ViewModel有如此的生命周期,所以ViewModel在MVVM可以作为数据存储区,是连接View和Model重要组件,ViewModel的核心作用如下图所示:
- 1.ViewModel是怎么创建的?
- 2.ViewModel是怎么存储的?
- 3.ViewModel为什么可以实现旋转屏幕不销毁?
先放简单讲一下ViewModel
的基本使用方法,我们在获取ViewModel
的时候绝对不能直接使用new
关键字去创建,需要使用 ViewModelProviders
去使用系统提供的反射方法去创建我们想要的ViewModel
,下面是官方架构组件android.arch.lifecycle包下面的ViewModelProviders
工具类用来获取ViewModel:
/** * 注解by danxx on 2018/3/31. * Global ViewModel Provider * ViewModel的创建不可直接new,需要使用这个{@link ViewModelProviders}才能与Activity或者 * Fragment的生命周期关联起来! */ public class ViewModelProviders { /** * 通过Activity获取可用的Application * 或者检测Activity是否可用 * @param activity * @return */ private static Application checkApplication(Activity activity) { Application application = activity.getApplication(); if (application == null) { throw new IllegalStateException("Your activity/fragment is not yet attached to " + "Application. You can't request ViewModel before onCreate call."); } return application; } /** * 通过Fragment获取Activity * 或者检测Fragment是否可用 * @param fragment * @return */ private static Activity checkActivity(Fragment fragment) { Activity activity = fragment.getActivity(); if (activity == null) { throw new IllegalStateException("Can't create ViewModelProvider for detached fragment"); } return activity; } /** * 通过Fragment获得ViewModelProvider * @param fragment * @return */ @NonNull @MainThread public static ViewModelProvider of(@NonNull Fragment fragment) { /**获取默认的单例AndroidViewModelFactory,它内部是通过反射来创建具体的ViewModel*/ ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance( checkApplication(checkActivity(fragment))); /*** * 利用HolderFragment来关联生命周期并使用HolderFragment中的ViewModelStore的HashMap存储ViewModel * AndroidViewModelFactory创建ViewModel */ return new ViewModelProvider(ViewModelStores.of(fragment), factory); } /** * 通过FragmentActivity获得ViewModelProvider * @param activity * @return */ @NonNull @MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity) { /**获取默认的单例AndroidViewModelFactory,它内部是通过反射来创建具体的ViewModel*/ ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance( checkApplication(activity)); /*** * 利用HolderFragment来关联生命周期并使用HolderFragment中的ViewModelStore的HashMap存储ViewModel * AndroidViewModelFactory创建ViewModel */ return new ViewModelProvider(ViewModelStores.of(activity), factory); } /** * * @param fragment * @param factory 提供了自定义创建ViewModel的方法 * @return */ @NonNull @MainThread public static ViewModelProvider of(@NonNull Fragment fragment, @NonNull ViewModelProvider.Factory factory) { //检测Fragment checkApplication(checkActivity(fragment)); return new ViewModelProvider(ViewModelStores.of(fragment), factory); } /** * * @param activity * @param factory 提供了自定义创建ViewModel的方法 * @return */ @NonNull @MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity, @NonNull ViewModelProvider.Factory factory) { //检测activity checkApplication(activity); return new ViewModelProvider(ViewModelStores.of(activity), factory); } }
有一些解释我已经放在注释里了,有兴趣的可以仔细看看。
开始创建使用ViewModel了:
1.在Activity中创建使用ViewModel:
/**转入Activity就行*/ GirlsViewModel girlsViewModel = ViewModelProviders.of(ActivityGirls.this).get(GirlsViewModel.class);
- 2.在Fragment中创建使用ViewModel:
/**转入Fragment就行*/ GirlsViewModel girlsViewModel = ViewModelProviders.of(FragmentGirls.this).get(GirlsViewModel.class);
3.在任意地方创建使用ViewModel:
/**将context强转成FragmentActivity就行*/ GirlsViewModel girlsViewModel = ViewModelProviders.of((FragmentActivity) context).get(GirlsViewModel.class);
ViewModel
的存在是依赖 Activity
或者 Fragment
的,不管你在什么地方获取ViewModel
,只要你用的是相同的Activity
或者 Fragment
,那么获取到的ViewModel
将是同一个 (前提是key
值是一样的),所以ViewModel
也具有数据共享的作用!
上面创建ViewModel
链式调用分解为下面两步:
/*****第一步:根据Activity或者Fragment获得ViewModelProvider****/ ViewModelProvider viewModelProvider = ViewModelProviders.of(ActivityGirls.this); /*****第二步:使用ViewModelProvider反射创建需要的ViewModel****/ GirlsViewModel girlsViewModel = viewModelProvider.get(GirlsViewModel.class);
先看第一步获得的源代码:
public static ViewModelProvider of(@NonNull FragmentActivity activity) { /**********获得AndroidViewModelFactory ( 内部是单例的 )*******/ ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance( checkApplication(activity)); /*****创建一个ViewModelProvider( 传入的两个参数是重点 )*****/ return new ViewModelProvider(ViewModelStores.of(activity), factory); }
上面的两步其实很关键了,获得AndroidViewModelFactory ,AndroidViewModelFactory
其实是ViewModelProvider
的静态内部类,看调用方式就知道是一个单例的,就是我们的应用只有有一个单例的 AndroidViewModelFactory
存在,看源码:
/*****`AndroidViewModelFactory `其实是`ViewModelProvider`的静态内部类******/ public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory { private static AndroidViewModelFactory sInstance; /********获得AndroidViewModelFactory 单例**********/ public static AndroidViewModelFactory getInstance(@NonNull Application application) { if (sInstance == null) { sInstance = new AndroidViewModelFactory(application); } return sInstance; } private Application mApplication; /*************其实构造方式是public 的,还是可以new的****************/ public AndroidViewModelFactory(@NonNull Application application) { mApplication = application; } /******其实这里就是创建ViewModel的关键地方,根据给出的Class反射创建需要的ViewModel*******/ @NonNull @Override public <T extends ViewModel> T create(@NonNull Class<T> 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); } }
重点我都标注在注释里了,请耐心看一遍。看到这里我知道了一个全局的AndroidViewModelFactory
工具类,作用就是反射创建我们想要的类ViewModel
,其实功能简单的!
获得到的单例AndroidViewModelFactory
是创建ViewModelProvider
的第二个参数,下面我们看第一个参数。
第一个参数是这样: ViewModelStores.of(activity)
看源码:
解释我就放在注释了,大家看下面的注释把:
@MainThread public static ViewModelStore of(@NonNull FragmentActivity activity) { //如果你的Activity实现了ViewModelStoreOwner接口具备了提供 //ViewModelStore 的功能就直接获取返回,通常我们的Activity都不会去实现这个功能 if (activity instanceof ViewModelStoreOwner) { return ((ViewModelStoreOwner) activity).getViewModelStore(); } //系统为你的Activity添加一个具有提供ViewModelStore 的holderFragment return holderFragmentFor(activity).getViewModelStore(); }
其实解析ViewModelStore
就可以解释ViewModel的存储,解析 holderFragmentFor(activity).getViewModelStore()
就可解释ViewModel为什么可以在Activity配置发生变化的情况下人不销毁,这些我们就在下面去解释。我第一步重点解释创建不关心其他的。
到这里我们要知道:
第一: AndroidViewModelFactory
在正常情况下是全局单例只有一个,只是一个反射创建对象的工具类。
第二:ViewModelProvider
是每次获取创建ViewModel
的时候都会创建一个新的。
第三:ViewModelStore
是每一个Activity或者Fragment都有一个。
关注ViewModel
创建:
java
//viewModelProvider的get方法
viewModelProvider.get(GirlsViewModel.class);
会用 DEFAULT_KEY 和 类名组成一个key值去获取,接着向下看:
代码很简单,流程如下:
(1) 先从mViewModelStore
中使用key去获取ViewModel
, mViewModelStore
中是使用HashMap
去存储一个Activity
或者Fragment
的ViewModel
的。如果获取到就返回。
(2) 没获取到就使用单例mFactory
的create方法反射创建ViewModel
,create方法的代码在上面贴出来了。
(3) 使用Key存入mViewModelStore
并返回。
到这里ViewModel
的创建基本就是讲完了,但是可能还是有些懵逼。下面接着看吧。
创建一个ViewModelProvider
,使用ViewModelProvider
内部的全局单例AndroidViewModelFactory
来反射创建 ViewModel
,并把创建的ViewModel
存入传入的ViewModelStore
中!
存储就是要讲解ViewModelStore
了。
直接看源代码:
代码就这数的清的几行,就是一个 HashMap
用存储ViewModel。提供get
,put
,clear
三个方法。
上面说了ViewModelStore
是每一个Activity
或者ViewModel
都有一个的,当Activity
或者Fragment
销毁的时候就会调用clear
方法了。
ViewModelStore
被谁创建,被谁持有?――――――-> +_+
抢答:被HolderFragment
创建和持有!
HolderFragment
跟我们的Activity或者Fragment有什么关系?――――――-> +_+
抢答:当我们要给Activity或者Fragment创建ViewModel的时候,系统就会为Activity或者Fragment添加一个HolderFragment
,HolderFragment
中会创建持有一个ViewModelStore
。
HolderFragment
怎么创建怎么被添加?――――――-> +_+
这一步其实可以分解为下面的的样子:
/**为Activity或者Fragment创建ViewModelStore*/ ViewModelStore viewModelStore = ViewModelStores.of(activity); /**为本次的ViewModel获取创建一个ViewModelProvider*/ ViewModelProvider viewModelProvider = new ViewModelProvider(viewModelStore, factory);
完成了上面两步才可以这样: viewModelProvider.get(想要的ViewModel.class);
正是
“`java
/*为Activity或者Fragment创建ViewModelStore/
ViewModelStore viewModelStore = ViewModelStores.of(activity / fragment);
这步为我们的 activity / fragment 注入了一个`HolderFragment`,创建`HolderFragment`的时候会创建的时候会创建一个ViewModelStore实例,到这里也解释了一下 **ViewModelStore被谁创建,被谁持有?**的问题。 上面我有提过`ViewModelStoreOwner`这个接口,其实我们这里说的`HolderFragment`就是实现了这个接口的Fragment。 ###一句话总结`ViewModel`是怎么被存储的: 这是上面一句话总结`ViewModel`的创建: ![8.ViewModel创建一句话总结](https://upload-images.jianshu.io/upload_images/1813550-c0dff4d120123993.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 这句创建总结其实也说明了`ViewModel`的存储。 进一步解释: `ViewModel`是存储在当前`Activity / Fragment` 的 `HolderFragment` 中的`ViewModelStore`的HashMap中,我们可以`get`,`put`或者在`Activity / Fragment `销毁的时候`HolderFragment`会跟随销毁,在`HolderFragment`的`onDestroy`方法中调用`mViewModelStore`的`clear`方法。 ![9.HolderFragment伴随销毁时调用自己所有ViewModel的onCleared方法](https://upload-images.jianshu.io/upload_images/1813550-db43163bf333b8ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) # 三、ViewModel为什么可以实现旋转屏幕不销毁? ViewModel的创建获取方式是: 为`Activity / Fragment`创建一个`ViewModelStore`,获取到`AndroidViewModelFactory`单例,用这个两个数据创建一个`ViewModelProvider`,在创建的`ViewModelProvider`中可以get我们要的ViewModel。 为`Activity / Fragment`创建一个`ViewModelStore`,就是调用下面的方法: ![10.HolderFragment被注入到Activity / Fragment](https://upload-images.jianshu.io/upload_images/1813550-1180ced321358f27.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) holderFragmentFor(activity)源码: ![11.holderFragmentFor(activity)](https://upload-images.jianshu.io/upload_images/1813550-16f31a19779ee93f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ![12.单例的HolderFragmentManager](https://upload-images.jianshu.io/upload_images/1813550-f455d7387143265a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) holderFragmentFor(activity)方法每一步都有解释,很详细: ```java HolderFragment holderFragmentFor(FragmentActivity activity) { //获取Activity的FragmentManager FragmentManager fm = activity.getSupportFragmentManager(); //通过HOLDER_TAG在FragmentManager中需要HolderFragment HolderFragment holder = findHolderFragment(fm); //获得的HolderFragment不为空就返回 if (holder != null) { return holder; } //在Map<Activity, HolderFragment>缓存中获取HolderFragment //Activity为key,所以每一个Activity或者Fragment只会有一个HolderFragment holder = mNotCommittedActivityHolders.get(activity); //不为空就返回 if (holder != null) { return holder; } //在Application中注册一个所有Activity生命周期回调监听,这里只会注册一次 //这里注册Activity生命周期监听的目的是在Activity销毁的时候好移除Map<Activity, HolderFragment>中的对应数据 if (!mActivityCallbacksIsAdded) { mActivityCallbacksIsAdded = true; activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks); } //new HolderFragment()并通过fm添加到Activity并返回 holder = createHolderFragment(fm); //添加到Map<Activity, HolderFragment>缓存 mNotCommittedActivityHolders.put(activity, holder); //返回 return holder; }
- createHolderFragment()方法重点关注一下:
就是创建了一个HolderFragment
,使用传入的FragmentManager
添加进去!
这是上面调用的构造方法:
被设置setRetainInstance(true)
后的Fragment
添加到Activity
中去了,会怎么样?
setRetainInstance(boolean) 是
Fragment
中的一个方法。将这个方法设置为true就可以使当前Fragment在Activity重建时存活下来, 如果不设置或者设置为 false, 当前 Fragment 会在 Activity 重建时同样发生重建, 以至于被新建的对象所替代。
在setRetainInstance(boolean)为true的 Fragment (就是HolderFragment
)中放一个专门用于存储ViewModel
的Map, 这样Map中所有的ViewModel都会幸免于Activity的配置改变导致的重建,让需要创建ViewModel
的Activity, Fragment都绑定一个这样的Fragment(就是HolderFragment
), 将ViewModel存放到这个 Fragment 的 Map 中, ViewModel 组件就这样实现了。
实现原理就是巧妙滴借用了Fragment的setRetainInstance(true)属性。关于setRetainInstance更多介绍可以参考:Android应用开发:Fragment的非中断保存setRetaineInstance
我这里可以展示一下setRetainInstance(true)属性对生命周期的影响,在一个Activity中加入一个具有setRetainInstance(true)属性的Fragment:
三秒钟后展示出了我们的Fragment,生命周期如下:
然后我们点击模拟器的旋转屏幕按钮:
生命周期变化:
可以看到Activity因为配置改变了,调了onDestroy
方法,但是我们的setRetainInstance(true)
属性的Fragment
没有调用onDestroy
方法,说明Fragment得以幸存下来了。
退出当前Activity但是不退出应用后的生命周期:
这时候Activity和Fragment的onDestroy
生命周期方法先后被调用了。
在我的HolderFragment
的onDestroy
方法中,会调用mViewModelStore
中所有ViewModel
的onCleared
方法。
关于ViewModel的实现结构图可以参考如下:图片来源https://blog.csdn.net/zhuzp_blog/article/details/78910535
1.ViewModel
以键值对的形式存在Activity或者Fragment的HolderFragment
的 ViewModelStore
的HashMap中。
2.一个Activity或者Fragment可以有很多个ViewModel
。
3.一个Activity或者Fragment只会有一个HolderFragment
。
4.Activity或者Fragment的HolderFragment
会保存在全局单例的HolderFragmentManager
的HashMap中,在Activity或者Fragment销毁的时候会移除HashMap中对应的value。
5.因为ViewModel
是以Activity或者Fragment为存在基础,所以ViewModel
可以在当前Activity和Fragment中实现数据共享,前提是传入相同的key值。
转自Dawish:https://blog.csdn.net/u010072711/article/details/80035276
MVVM架构组件成员解析:
Android 架构组件(一)――Lifecycle
https://blog.csdn.net/zhuzp_blog/article/details/78871374
Android架构组件(二)――LiveData
https://blog.csdn.net/zhuzp_blog/article/details/78871527
Android架构组件(三)――ViewModel
https://blog.csdn.net/zhuzp_blog/article/details/78910535
ViewModel
是google官方的MVVM架构组件,目前已经集成到了最新的支持库中了,是MVVM架构的核心组件之一。不懂MVVM的请看之前的文章:(一)Android官方MVVM框架实现组件化之整体结构
网上看到的ViewModel的博文千篇一律,实在忍不了,自己写看了源码写了一篇,欢迎拍砖!
ViewModel是存储UI相关数据并不会因为旋转而销毁的类。
最为重要的就是ViewModel具有下面的生命周期,这就是ViewModel的最可贵之处:
正因为ViewModel有如此的生命周期,所以ViewModel在MVVM可以作为数据存储区,是连接View和Model重要组件,ViewModel的核心作用如下图所示:
- 1.ViewModel是怎么创建的?
- 2.ViewModel是怎么存储的?
- 3.ViewModel为什么可以实现旋转屏幕不销毁?
先放简单讲一下ViewModel
的基本使用方法,我们在获取ViewModel
的时候绝对不能直接使用new
关键字去创建,需要使用 ViewModelProviders
去使用系统提供的反射方法去创建我们想要的ViewModel
,下面是官方架构组件android.arch.lifecycle包下面的ViewModelProviders
工具类用来获取ViewModel:
/** * 注解by danxx on 2018/3/31. * Global ViewModel Provider * ViewModel的创建不可直接new,需要使用这个{@link ViewModelProviders}才能与Activity或者 * Fragment的生命周期关联起来! */ public class ViewModelProviders { /** * 通过Activity获取可用的Application * 或者检测Activity是否可用 * @param activity * @return */ private static Application checkApplication(Activity activity) { Application application = activity.getApplication(); if (application == null) { throw new IllegalStateException("Your activity/fragment is not yet attached to " + "Application. You can't request ViewModel before onCreate call."); } return application; } /** * 通过Fragment获取Activity * 或者检测Fragment是否可用 * @param fragment * @return */ private static Activity checkActivity(Fragment fragment) { Activity activity = fragment.getActivity(); if (activity == null) { throw new IllegalStateException("Can't create ViewModelProvider for detached fragment"); } return activity; } /** * 通过Fragment获得ViewModelProvider * @param fragment * @return */ @NonNull @MainThread public static ViewModelProvider of(@NonNull Fragment fragment) { /**获取默认的单例AndroidViewModelFactory,它内部是通过反射来创建具体的ViewModel*/ ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance( checkApplication(checkActivity(fragment))); /*** * 利用HolderFragment来关联生命周期并使用HolderFragment中的ViewModelStore的HashMap存储ViewModel * AndroidViewModelFactory创建ViewModel */ return new ViewModelProvider(ViewModelStores.of(fragment), factory); } /** * 通过FragmentActivity获得ViewModelProvider * @param activity * @return */ @NonNull @MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity) { /**获取默认的单例AndroidViewModelFactory,它内部是通过反射来创建具体的ViewModel*/ ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance( checkApplication(activity)); /*** * 利用HolderFragment来关联生命周期并使用HolderFragment中的ViewModelStore的HashMap存储ViewModel * AndroidViewModelFactory创建ViewModel */ return new