本文整体流程:首先要知道什么是 ViewModel,然后演示一个例子,来看看 ViewModel 是怎么使用的,接着提出问题为什么是这样的,最后读源码来解释原因!
1.什么是ViewModel
1.1.定义
ViewModel
类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel
类让数据可在发生屏幕旋转等配置更改后继续留存。在对应的作用域内,保正只生产出对应的唯一实例,保证UI组件间的通信。
ViewModel 一般要配合 LiveData、DataBinding一起使用
1.2.特点
通过定义我们可以得出
- ViewModel不会随着Activity的屏幕旋转而销毁;
- 在对应的作用域内,保正只生产出对应的唯一实例,保证UI组件间的通信
重点说一下ViewModel和onSaveInstanceState的关系
-
对于简单的数据,Activity 可以使用
onSaveInstanceState()
方法从onCreate()
中的捆绑包恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。 -
ViewModel存储大量数据,不用序列化与反序列化
-
onSaveInstanceState存储少量数据
-
相辅相成,不是替代
-
进程关闭是onSaveInstanceState的数据会保留,而ViewModel销毁
2.ViewModel的基础使用
这个例子,主要是在 打印 User 的信息,并且点击按钮的时候更新 User 的信息并打印
2.1首先看一下 UserViewModel这个文件
//UserViewModel.kt
//自定义 User 数据类
data class User(var userId: String = UUID.randomUUID().toString(), var userName: String)
class UserViewModel : ViewModel() {
private val userBean = User(userName = "刀锋之影")
// 私有的 user LiveData
private val _user = MutableLiveData<User>().apply {
value = userBean
}
// 对外暴露的,不可更改 value 值的LiveData
var userLiveData: LiveData<User> = _user
//更新 User 信息
fun updateUser() {
//重新给 _user 赋值
_user.value = userBean.apply {
userId = UUID.randomUUID().toString()
userName = "更新后: userName = 泰隆"
}
}
}
- 自定义 User 数据类
- 继承ViewModel,初始化 User
- 声明私有的 user LIveData 用来更新数据
- 对外暴露的,不可更改 value 值的LiveData
- updateUser() 更新 User 信息的方法
2.2.再看下ViewModelActivity的内容
class ViewModelActivity : AppCompatActivity() {
//初始化 UserViewModel 通过 ViewModelProvider
private val userViewModel by lazy {
ViewModelProvider(this)[UserViewModel::class.java] }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val button = Button(this)
setContentView(button)
//观察 User 数据,并打印
userViewModel.userLiveData.observe(this, Observer {
user ->
"User = $user".log()
})
//点击按钮更新 User 信息
button.setOnClickListener {
userViewModel.updateUser()
}
}
}
- 初始化 UserViewModel
- 观察 User 数据,并打印结果
- 点击按钮时,更新 User 信息
2.3.结果日志
//log 日志
User = User(userId=34c1a1a4-967e-439c-91e8-795b8c162997, userName=刀锋之影)
User = User(userId=a6d0f09c-9c01-412a-ab4f-44bef700d298, userName=更新后: userName = 泰隆)
2.4总结:
以上就是 ViewModel 的简单使用,是配合 LiveData 的,具体 LiveData 的使用以及与原理分析,请看这篇文章
Android Jetpack组件LiveData基本使用和原理分析
通过上文可以 ViewModel 的定义以及特点,可以知道 ViewModel在对应的作用域内,保正只生产出对应的唯一实例,保证UI组件间的通信
我们来验证一下这个特点,我再写个例子,证明一下这个特点
3.验证ViewModel在对应的作用域内,保正只生产出对应的唯一实例
3.1.ViewModelActivity2类
在ViewModelActivity2中通过supportFragmentManager添加两个 Fragment
class ViewModelActivity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_model)
supportFragmentManager.beginTransaction()
.add(R.id.flContainer, FirstFragment())
.add(R.id.flContainer, SecondFragment())
.commit()
}
}
3.2.两个 Fragment
class FirstFragment : Fragment() {
private val TAG = javaClass.simpleName
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val userViewModel = ViewModelProvider(activity as ViewModelStoreOwner)[UserViewModel::class.java]
"userViewModel = $userViewModel".logWithTag(TAG)
return super.onCreateView(inflater, container, savedInstanceState)
}
}