声明 : https://www.jianshu.com/p/714062a9af75
🌸 简介:
为了能更好的划分职能,Android 为我们提供了 ViewModel 类,专门用于存放应用程序页面所需要的数据.ViewModel 是将页面所需要的数据从页面中剥离出来,页面只需要处理用户交互和展示数据.
ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel类让数据可在发生屏幕旋转等配置更改后继续存在.
🌸 生命周期:
来自官网:
image.png
屏幕旋转锁导致 Activity 重建,并不会影响 ViewModel 的声明周期
🌸 原理:
看原理之前呢,先看看下面的使用方法哈~~~
在页面中通过 ViewModelProvider 来实例化一个 ViewModel. ViewModelProvider 接受一个ViewModelStoreOwner类型的对象作为参数,我们实例化的是传的 this,代指当前的 Activity,这是因为我们的 Activity 集成自 ComponentActivity,而ComponentActivity默认实现了ViewModelStoreOwner接口.
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner {
........
@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) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
}
接口里面的方法返回的类型为ViewModelStore,从下面ViewModelStore的源码中可以看出来,ViewModel是以 HashMap 的形式被缓存了起来.ViewModel和界面之间没有直接的链接.他们通过ViewModelProvider进行关联,当页面需要 ViewModel 时,会向ViewModelProvider索要, ViewModelProvider会去 HashMap中查找,如果存在,直接返回,不存在,会实例化一个.
public class ViewModelStore {
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();
}
}
//........
}
⚠️⚠️⚠️敲黑板⚠️⚠️⚠️
我们在使用ViewModel的时候,要特别注意.Activity由于配置变化导致的销毁重建不会影响ViewModel,ViewModel是独立于页面的,所以不要向ViewModel中传入任何类型的 Context 或者带有 Context 的引用对象,避免内存泄漏
除了 Activity 实现了ViewModelStoreOwner接口外,Fragment 也实现了,,也可以正常使用 ViewModel.
🌸 使用方法
1,build.gradle 文件
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
2,创建 ViewModel 的类
class TestModel : ViewModel() {
var number = 0
//Activty 销毁时,才会被调用
override fun onCleared() {
super.onCleared()
}
}
ViewModel 是一个抽象类,其中有一个方法 onCleared().当 与 ViewModel 相关的Activity被销毁时,该方法才会被调用.我们可以在这个方法里面执行一些资源释放的相关操作,比如,取消倒计时之类的.但是,由于屏幕旋转二]而导致Activity重新创建,并不会调用这个方法.
3,在TestActivity中使用
class TestActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
var testModel = ViewModelProvider(this).get(TestModel::class.java)
textView1.text = testModel.number.toString()
button_send.setOnClickListener(View.OnClickListener {
testModel.number = testModel.number + 1
textView1.text = testModel.number.toString()
})
}
}
通过ViewModelProvider 实例化 ViewModel,ViewModelProvider会判断是否存在,若存在,会直接返回,若不存在,则会创建一个 ViewModel.
好了,看图:
🌸 ViewModel 和 AndroidViewModel
ViewModel 不能将任何类型的 Context 或者含有 Context 引用的对象传入 ViewModel,因为会引起内存泄漏,但是AndroidViewModel可以,它集成自 ViewModel,并接收 Applicatoin 作为 Context.它的生命周期是和 Application 一样的,所以不算内存泄漏.
🌸 ViewModel 和 onSaveInstanceState()
one:💁 onSaveInstanceState()只能保存少量的,支持序列化的数据,但是 ViewModel 没有这个限制.ViewModel 能保存页面中所有的数据,
two:💁 ViewModel不支持数据的持久化,当界面被彻底销毁时,ViewModel 中的数据就不存在了,但是onSaveInstanceState支持数据的持久化.
二者,各有千秋.
网友评论