那ViewModel为什么可以管理这些数据呢?
主要还是因为ViewModel的生命周期比Activtiy、Fragment生命周期来的更长。
Activity或Fragment这类应用组件都有自己的生命周期,他们的生命周期都是被Framework所管理。Framework可能会根据用户的一些操作以及设备的状态对Activity或Fragment进行销毁和重建。作为开发者,这些行为我们是无法干预的。伴随着Activity或Fragment的销毁和重建,它们当中的数据也会随着一起销毁和重建。对于一些简单的数据,Activity可以使用onSaveInstanceState()方法,并从onCreate的bundle中重新获取,但这一方法仅仅适合一些简单的UI状态,对于列表型这种庞大的数据类型并不适合。
Activity或Fragment经常会做一些异步的耗时操作,随之就需要管理这些异步操作得到的数据,并在destroyed的时候清理它们,从而避免内存溢出这类问题的发生。但是这样的处理会随着项目扩大而变得十分复杂。
Activity或Fragment本身需要处理很多用户的输入事件并和操作系统打交道,当它们还要花时间管理那些数据资源时,它们所在的类就会变得异常庞大,造就出所谓的god activities和god fragments,这样很尴尬。
所以引入ViewModel之后,数据就可以从UI中分离出来,让每个模块的职责更加清晰合理。并且当Activity或Fragment重建的时候,ViewModel会自动保留之前的数据并给新的Activity或Fragment使用。
1. 数据持久化
在屏幕旋转的时候会经历 Activity 的销毁与重新创建,这里就涉及到数据保存的问题,显然重新请求或加载数据是不友好的。在ViewModel 出现之前我们可以用 Activity 的 onSaveInstanceState() 机制保存和恢复数据,但缺点很明显,onSaveInstanceState只适合保存少量的可以被序列化、反序列化的数据,这种机制明显不合适。
ViewModel 生命周期图如下:
由图可知,ViewModel 生命周期是贯穿整个 activity 生命周期,包括 Activity 因旋转造成的重创建,直到 Activity 真正意义上销毁后才会结束。既然如此,用来存放数据再好不过了。
2. 异步回调问题
通常我们 App 需要频繁异步请求数据,比如调接口请求服务器数据。当然这些请求的回调都是相当耗时的,之前我们在 Activity 或Fragment里接收这些回调。所以不得不考虑潜在的内存泄漏情况,比如 Activity被销毁后接口请求才返回。处理这些问题,会给我们增添好多复杂的工作。但现在我们利用 ViewModel处理数据回调,可以完美的解决此痛点。意思只要继承我们的ViewModel后,可能会出现的bug,google都帮我们处理了。
3. 分担 UI controller 负担
从最早的 MVC 到目前流行的 MVP、MVVM,目的无非是 明确职责,分离 UI Controller 负担。 UI Controller比如 Activity 、Fragment是设计用来渲染展示数据、响应用户行为、处理系统的某些交互。如果再要求他去负责加载网络或数据库数据,会让其显得臃肿和难以管理。
所以为了简洁、清爽、丝滑,我们可以分离出数据操作的职责给 ViewModel。
4. Fragments 间共享数据
比如在一个 Activity 里有多个 Fragment,这 Fragment 之间需要做某些交互。我之前的做法是接口回调,需要统一在 Activity 里管理,并且不可避免的 Fragment 之间还得互相持有对方的引用。
val mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
官网地址
java
def lifecycle_version = "2.2.0"
def arch_version = "2.1.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
kotlin
def lifecycle_version = "2.2.0"
def arch_version = "2.1.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
1. 创建一个ViewModel类
继承ViewModel,需要注意的是ViewModel类中不应该持有Activity、Fragment、view的引用。
架构组件为UI控制器提供ViewModel助手类,ViewModel对象在配置更改期间会自动保留,以便它们保存的数据立即可用于下一个Activity或fragment实例。例如,如果您需要在应用中显示用户列表,请明确分配职责来获取数据并将用户列表保存到ViewModel,而不是Activity或fragment。
ViewModel一般配合 LiveData 使用。
class MainViewModel : ViewModel() {
val mutableLiveData = MutableLiveData<String>()
fun loadData() {
mutableLiveData.value = "zly"
}
}
2. 然后你可以从一个Activity中加载数据,如下所示:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//获取ViewModel
val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
//加载数据
viewModel.loadData()
viewModel.mutableLiveData.observe(this, Observer {
Log.e("xyh", "onCreate: $it")
})
}
}
如果Activity重新创建,它将接收由第一个Activity创建的相同的ViewModel实例。当持有ViewModel的Activity finish后,框架将调用ViewModel对象的onCleared()方法,以便它可以清理资源。
方式1
2.2.0-alpha02 以前的版本是通过下面的方式,新版本已弃用。
val viewModel1 = ViewModelProviders.of(this).get(MainViewModel::class.java)
需要加入依赖 :
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
方式2
代码中只有一个this参数。
val mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
this参数一般为Activity或Fragment,因此ViewModelProvider可以获取组件的生命周期。
方式3
val viewMode = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())
.get(MainViewModel::class.java)
方式4
val viewModel = ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory
.getInstance(application)).get(MainViewModel::class.java)
方式5
val viewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(application)
.create(MainViewModel::class.java)
方式6
val viewModel = ViewModelProvider(viewModelStore,defaultViewModelProviderFactory).get(MainViewModel::class.java)
class MainViewModel(val name: String) : ViewModel() {
val mutableLiveData = MutableLiveData<String>()
fun loadData() {
mutableLiveData.value = "zly$name"
}
class MainViewModelFactory(private val name: String) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MainViewModel(name) as T
}
}
}
val viewModel = ViewModelProvider(this,MainViewModel.MainViewModelFactory("20"))
.get(MainViewModel::class.java)
VmFactory
/**
* Cerated by xiaoyehai
* Create date : 2021/1/25 17:36
* description : 封装工厂类获取ViewModel
*/
class VmFactory(private val application: Application) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(OneViewModel::class.java)) {
return OneViewModel() as T
} else if (modelClass.isAssignableFrom(TwoViewModel::class.java)) {
return TwoViewModel(application) as T
} else {
throw ClassNotFoundException("class $modelClass 没有注册到工厂类这个viewModel啊")
}
}
}
OneViewModel
class OneViewModel : ViewModel() {
val mutableLiveData = MutableLiveData<String>()
fun loadData() {
mutableLiveData.value = "zly"
}
}
TwoViewModel
class TwoViewModel(application: Application):AndroidViewModel(application) {
}
使用
val viewModel = VmFactory(application).create(OneViewModel::class.java)
//加载数据
viewModel.loadData()
viewModel.mutableLiveData.observe(this, Observer {
Log.e("xyh", "onCreate: $it")
})
使用AndroidViewModel:
class MainViewModel(application: Application) : AndroidViewModel(application) {
fun login() {
Toast.makeText(getApplication(),"登陆成功",Toast.LENGTH_SHORT).show()
}
}
获取viewModel的方式不变:
val viewModel = ViewModelProvider(this).get(MainViewModel::class.java);
viewModel.login()
下面是AndroidViewModel的源码:
public class AndroidViewModel extends ViewModel {
@SuppressLint("StaticFieldLeak")
private Application mApplication;
public AndroidViewModel(@NonNull Application application) {
mApplication = application;
}
/**
* Return the application.
*/
@SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"})
@NonNull
public <T extends Application> T getApplication() {
return (T) mApplication;
}
}
class ShareViewModel:ViewModel() {
private val mutableLiveData = MutableLiveData<String>()
fun setData(value:String) {
mutableLiveData.value = value
}
fun getData(): LiveData<String> {
return mutableLiveData
}
}
class Fragment1 : Fragment() {
private lateinit var mBinding: Fragment1Binding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mBinding = DataBindingUtil.inflate<Fragment1Binding>(
inflater,
R.layout.fragment1,
container,
false
)
return mBinding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val viewModel = ViewModelProvider(activity!!).get(ShareViewModel::class.java)
mBinding.btn.setOnClickListener {
viewModel.setData("xyh")
}
}
}
class Fragment2 : Fragment() {
private lateinit var mBinding: Fragment2Binding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mBinding = DataBindingUtil.inflate<Fragment2Binding>(
inflater,
R.layout.fragment2,
container,
false
)
return mBinding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val viewModel = ViewModelProvider(activity!!).get(ShareViewModel::class.java)
viewModel.getData().observe(viewLifecycleOwner, Observer {
mBinding.tv.text = it
})
}
}
val viewModel = ViewModelProvider(activity!!).get(ShareViewModel::class.java)
这种方式的好处包括:
ViewModel职责是为Activity或Fragment管理、请求数据,具体数据请求逻辑不应该写在ViewModel中,否则ViewModel的职责会变得太重,此处需要一个引入一个Repository,负责数据请求相关工作。具体请参考 Android架构组件。
ViewModel可以用于Activity内不同Fragment的交互,也可以用作Fragment之间一种解耦方式。
ViewModel也可以负责处理部分Activity/Fragment与应用其他模块的交互。
ViewModel生命周期(以Activity为例)起始于Activity第一次onCreate(),结束于Activity最终finish时。
override fun onRetainCustomNonConfigurationInstance(): Any? {
Log.e("xyh", "onRetainCustomNonConfigurationInstance: ")
return super.onRetainCustomNonConfigurationInstance()
}
override fun getLastCustomNonConfigurationInstance(): Any? {
Log.e("xyh", "getLastCustomNonConfigurationInstance: ")
return super.getLastCustomNonConfigurationInstance()
}
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci; //保存的内容
}
NonConfigurationInstances mLastNonConfigurationInstances;
//获取上次切换时的内容
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
static final class NonConfigurationInstances {
Object activity;
HashMap<String, Object> children;
FragmentManagerNonConfig fragments;
ArrayMap<String, LoaderManager> loaders;
VoiceInteractor voiceInteractor;
}
val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
我们看看getViewModelStore方法:
@NonNull
@Override
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
//第一次:mViewModelStore 为null
if (mViewModelStore == null) {
//第一次:nc 为null
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
//第一次,mViewModelStore为空,就创建一个mViewModelStore
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
ViewModelStore :
用于缓存ViewModel的一个操作类。
public class ViewModelStore {
//用于存储ViewModel的集合
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();
}
}
ViewModel的保存, 是在ViewModelProvider的get方法中:
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
//获取我们传入的ViewModel简称(就这样叫吧),作为key的一部分
String canonicalName = modelClass.getCanonicalName();
//判断是不是局部类与匿名类
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
//获取ViewModel实例
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//从集合中获取ViewModel并检测是不是已经实例化,如果存在就不要新建
ViewModel viewModel = mViewModelStore.get(key);
//判断viewModel是否是modelClass类的实例
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
//如果是则直接返回已存在的viewModel
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
//否则通过工厂来新生成一个viewModel实例,用反射获取到ViewModel的实例
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
//把新生成的viewModel实例存入mViewModelStore中
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
其实主要还是利用了反射得到了ViewModel的实例。我们才可以使用ViewModel里面的方法。
那么什么是反射呢? 这里简单介绍一下:
反射机制:反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
优点:可以实现动态创建对象和编译,体现出很大的灵活性
缺点:对性能有影响,此类操作总是慢于直接执行相同的操作
系统配置发生变化时会走回调下面的方法:
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
//如果当前的mViewModelStore为空,会先向nc中取mViewModelStore,这里边存储的就是上一次Activity对应的实例的mViewModelStore
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
//保存viewModelStore 到 NonConfigurationInstances
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
当配置发生更改时一般会造成数据丢失,而NonConfigurationInstances实例则可以在配置发生变化时保存一些数据和状态,在oncreate方法恢复使数据不会丢失。
当配置发生变化的时候它保存了ViewModelStore。所以这里先从NonConfigurationInstance实例中获取ViewModelStore。
这里的关键是NonConfigurationInstances。在设备旋转的时候,当前Activity被销毁了,mViewModelStore等数据会被封装到NonConfigurationInstances中存储
val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
@NonNull
@Override
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// 获取到viewModelStore
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//获取到ViewModel
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;
}
最后说一下VierModel是如何销毁的
/**
* 在FragmentActivity的onDestroy方法中调用了mViewModelStore.clear()
*/
@Override
protected void onDestroy() {
super.onDestroy();
//isChangingConfigurations:系统配置发生变化(如屏幕旋转)
if (mViewModelStore != null && !isChangingConfigurations()) {
mViewModelStore.clear();
}
mFragments.dispatchDestroy();
}
/**
* 先遍历ViewModel实例 调用各自的clear()
* 再清除集合中的ViewModel实例
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
/**
* 清除一些标记 并调用onCleared()
*/
@MainThread
final void clear() {
mCleared = true;
// Since clear() is final, this method is still called on mock objects
// and in those cases, mBagOfTags is null. It'll always be empty though
// because setTagIfAbsent and getTag are not final so we can skip
// clearing it
if (mBagOfTags != null) {
synchronized (mBagOfTags) {
for (Object value : mBagOfTags.values()) {
// see comment for the similar call in setTagIfAbsent
closeWithRuntimeException(value);
}
}
}
onCleared();
}
//通过继承ViewModel 可以重写该方法。 该方法会在ViewMode被销毁前调用
protected void onCleared() {
}
通过源码分析ViewModel有三个重要的类:ViewModel 、ViewModelProvider 、 ViewModelStore
ViewModel :负责准备和管理数据的类,该抽象类其实是声明一些通用方法。
ViewModelProvider :ViewModel 的核心类,主要是利用反射实例化出ViewModel 对象。利用工厂模式生产出具体的ViewModel 实例。
ViewModelStore:缓存ViewModel实例的一些操作(存储、获取、清除)
核心原理简单通俗描述如下: