当前位置:网站首页>学会使用LiveData和ViewModel,我相信会让你在写业务时变得轻松
学会使用LiveData和ViewModel,我相信会让你在写业务时变得轻松
2022-07-01 13:19:00 【InfoQ】
前言:
介绍
LiveData和ViewModel的关系:

LiveData
使用 LiveData 具有以下优势:
- UI与数据状态匹配
- LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知
Observer对象。您可以整合代码以在这些Observer对象中更新界面。这样一来,您无需在每次应用数据发生变化时更新界面,因为观察者会替您完成更新。
- 提高代码的稳定性
- 代码稳定性在整个应用程序生命周期中增加:
- 活动停止时不会发生崩溃。如果应用程序组件处于非活动状态,则这些更改不受影响。因此,您在更新数据时无需担心应用程序组件的生命周期。对于后台堆栈中的活动,它不会接受任何LiveData事件
- 内存泄漏会减少,观察者会绑定到Lifecycle对象,并在其关联的生命周期遭到销毁后进行自我清理
- 取消订阅任何观察者时无需担心
- 如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。
- 不再需要手动处理生命周期
- 界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。
- 数据始终保持最新状态
- 如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。
- 共享资源
- 像单例模式一样,我们也可以扩展我们的LiveData对象来包装系统服务,以便它们可以在我们的应用程序中共享。一旦LiveData对象连接到系统服务,任何需要资源的观察者可以轻松地观看LiveData对象。
在以下情况中,不要使用LiveData:
- 您需要在信息上使用大量运算符,尽管LiveData提供了诸如转换之类的工具,但只有Map和switchMap可以帮助您
- 您没有与信息的UI交互
- 您有一次性的异步操作
- 您不必将缓存的信息保存到UI中
如何使用LiveData
基础使用流程:
class MainViewModel : ViewModel() {
var mycount: MutableLiveData<Int> = MutableLiveData()
}
class MainActivity : AppCompatActivity() {
lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
...
/**记住绝对不可以直接去创建ViewModel实例
一定要通过ViewModelProvider(ViewModelStoreOwner)构造函数来获取。
因为每次旋转屏幕都会重新调用onCreate()方法,如果每次都创建新的实例的话就无法保存数据了。
用上述方法后,onCreate方法被再次调用,
它会返回一个与MainActivity相关联的预先存在的ViewModel,这就是保存数据的原因。*/
viewModel = ViewModelProvider([email protected],ViewModelProvider.
NewInstanceFactory()).get(MainViewModel::class.java)
}
}
/**
* 订阅 ViewModel,mycount是一个LiveData类型 可以观察
* */
viewModel.mycount.observe([email protected]) {
countTv.text = viewModel.mycount.value.toString()
}
// LiveData onchange会自动感应生命周期 不需要手动
// viewModel.mycount.observe(this, object : Observer<Int> {
// override fun onChanged(t: Int?) {
//
// }
// })
进阶用法:
//实体类
data class User(var name: String)
...
//Transformations.map接收两个参数,第一个参数是用于转换的LiveData原始对象,第二个参数是转换函数。
private val userLiveData: MutableLiveData<User> = MutableLiveData()
val userNames: LiveData<String> = Transformations
.map(userLiveData) { user ->
user.name
}
data class Student
(var englishScore: Double, var mathScore: Double, val scoreTAG: Boolean)
.....
class SwitchMapViewModel:ViewModel {
var studentLiveData = MutableLiveData<Student>()
val transformationsLiveData = Transformations.switchMap(studentLiveData) {
if (it.scoreTAG) {
MutableLiveData(it.englishScore)
} else {
MutableLiveData(it.mathScore)
}
}
}
//使用时:
var student = Student()
person.englishScore = 88.2
person.mathScore = 91.3
//判断显示哪个成绩
person.condition = true
switchMapViewModel.conditionLiveData.postValue(person)
class MediatorLiveDataViewModel : ViewModel() {
var liveDataA = MutableLiveData<String>()
var liveDataB = MutableLiveData<String>()
var mediatorLiveData = MediatorLiveData<String>()
init {
mediatorLiveData.addSource(liveDataA) {
Log.d("This is livedataA", it)
mediatorLiveData.postValue(it)
}
mediatorLiveData.addSource(liveDataB) {
Log.d("This is livedataB", it)
mediatorLiveData.postValue(it)
}
}
}
解释:
- MutableLiveData的父类是LiveData
- LiveData在实体类里可以通知指定某个字段的数据更新
- MutableLiveData则是完全是整个实体类或者数据类型变化后才通知.不会细节到某个字段。
原理探究:
- LiveData的工作原理
- LiveData的observe方法源码分析
- LifecycleBoundObserver源码分析
- activeStateChanged源码分析(用于粘性事件)
- postValue和setValue
- considerNotify判断是否发送数据分析
- 粘性事件的分析
ViewModel
官方简介
生命周期

基础使用流程:
class MainViewModel : ViewModel() {
...
}
//第一种 ViewModelProvider直接获取
ViewModelProvider([email protected]).get(MainViewModel::class.java)
//第二种 通过 ViewModelFactory 创建
class TestViewModelFactory(private val param: Int) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return TestViewModel(param) as T
}
}
ViewModelProvider([email protected],TestViewModelFactory(0)).get(TestViewModel::class.java)
ViewModel常见的使用场景
- 使用ViewModel,在横竖屏切换后,Activity重建,数据仍可以保存
- 同一个Activity下,Fragment之间的数据共享
- 与LiveData配合实现代码的解耦
ViewModel和onSaveInstanceState的区别
ViewModel和Context
案例一:计数器 — 两个Activity共享一个ViewModel

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class MainViewModel : ViewModel() {
private var _mycount: MutableLiveData<Int> = MutableLiveData()
//只暴露不可变的LiveData给外部
val mycount: LiveData<Int> get() = _mycount
init {
//初始化
_mycount.value = 0
}
/**
* mycount.value若为空就赋值为0,不为空则加一
* */
fun add() {
_mycount.value = _mycount.value?.plus(1)
}
/**
* mycount.value若为空就赋值为0,不为空则减一,可以为负数
* */
fun reduce() {
_mycount.value = _mycount.value?.minus(1)
}
/**
* 随机参数
* */
fun random() {
val random = (0..100).random()
_mycount.value = random
}
/**
* 清除数据
* */
fun clear() {
_mycount.value = 0
}
}
import androidx.lifecycle.*
/**
* 用于标记viewmodel的作用域
*/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
annotation
class VMScope(val scopeName: String) {}
private val vMStores = HashMap<String, VMStore>()
fun LifecycleOwner.injectViewModel() {
//根据作用域创建商店
this::class.java.declaredFields.forEach { field ->
field.getAnnotation(VMScope::class.java)?.also { scope ->
val element = scope.scopeName
var store: VMStore
if (vMStores.keys.contains(element)) {
store = vMStores[element]!!
} else {
store = VMStore()
vMStores[element] = store
}
val clazz = field.type as Class<ViewModel>
val vm = ViewModelProvider(store, ViewModelProvider.NewInstanceFactory()).get(clazz)
field.set(this, vm)
}
}
}
class VMStore : ViewModelStoreOwner {
private var vmStore: ViewModelStore? = null
override fun getViewModelStore(): ViewModelStore {
if (vmStore == null)
vmStore = ViewModelStore()
return vmStore!!
}
}
class MainActivity : AppCompatActivity() {
@VMScope("count") //设置作用域
lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
injectViewModel()
initEvent()
}
private fun initEvent() {
val cardReduce: CardView = findViewById(R.id.card_reduce)
.....
cardReduce.setOnClickListener {
//调用自定义ViewModel中的方法
viewModel.reduce()
}
.....
/**
* 订阅 ViewModel,mycount是一个LiveData类型 可以观察
* */
viewModel.mycount.observe([email protected]) {
countTv.text = viewModel.mycount.value.toString()
}
}
在第二个Activity中也是类似...
案例二:同一个Activity下的两个Fragment共享一个ViewModel

class BlankViewModel : ViewModel() {
private val numberLiveData = MutableLiveData<Int>()
private var i = 0
fun getLiveData(): LiveData<Int> {
return numberLiveData
}
fun addOne(){
i++
numberLiveData.value = i
}
}
//左Fragment
class LeftFragment : Fragment() {
private val viewModel:BlankViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_left, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//对+1按钮监听
left_button.setOnClickListener {
viewModel.addOne()
}
activity?.let {it ->
viewModel.getLiveData().observe(it){
left_text.text = it.toString()
}
}
}
}
//右Fragment
class RightFragment : Fragment() {
private val viewModel: BlankViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_right, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
right_button.setOnClickListener {
viewModel.addOne()
}
activity?.let { it ->
viewModel.getLiveData().observe(it) {
right_text.text = it.toString()
}
}
}
}
尾述
关于我
边栏推荐
- String input function
- MySQL六十六问,两万字+五十图详解!复习必备
- Several models of IO blocking, non blocking, IO multiplexing, signal driven and asynchronous IO
- 数字化转型再下一城,数字孪生厂商优锘科技宣布完成超3亿元融资
- 机器学习总结(一):线性回归、岭回归、Lasso回归
- Svg diamond style code
- Computer network interview knowledge points
- Meta enlarge again! VR new model posted on CVPR oral: read and understand voice like a human
- Global and Chinese styrene acrylic lotion polymer development trend and prospect scale prediction report Ⓒ 2022 ~ 2028
- [development of large e-commerce projects] performance pressure test - basic concept of pressure test & jmeter-38
猜你喜欢

Spark source code (V) how does dagscheduler taskscheduler cooperate with submitting tasks, and what is the corresponding relationship between application, job, stage, taskset, and task?

流量管理技术

图灵奖得主Judea Pearl:最近值得一读的19篇因果推断论文

Terminal identification technology and management technology

Chen Yu (Aqua) - Safety - & gt; Cloud Security - & gt; Multicloud security
![[development of large e-commerce projects] performance pressure test - basic concept of pressure test & jmeter-38](/img/50/819b9c2f69534afc6dc391c9de5f05.png)
[development of large e-commerce projects] performance pressure test - basic concept of pressure test & jmeter-38

香港科技大学李泽湘教授:我错了,为什么工程意识比上最好的大学都重要?
![[machine learning] VAE variational self encoder learning notes](/img/38/3eb8d9078b2dcbe780430abb15edcb.png)
[machine learning] VAE variational self encoder learning notes

Flow management technology

SVG钻石样式代码
随机推荐
Function test process in software testing
Have you ever encountered the problem that flynk monitors the PostgreSQL database and checkpoints cannot be used
Computer network interview knowledge points
VM virtual machine configuration dynamic IP and static IP access
运行游戏时出现0xc000007b错误的解决方法[通俗易懂]
Global and Chinese n-butanol acetic acid market development trend and prospect forecast report Ⓧ 2022 ~ 2028
龙蜥社区开源 coolbpf,BPF 程序开发效率提升百倍
Simple two ball loading
Apache-Atlas-2.2.0 独立编译部署
China NdYAG crystal market research conclusion and development strategy proposal report Ⓥ 2022 ~ 2028
洞态在某互联⽹⾦融科技企业的最佳落地实践
[Niu Ke's questions -sql big factory interview real questions] no2 User growth scenario (a certain degree of information flow)
Global and Chinese silicone defoamer production and marketing demand and investment forecast analysis report Ⓨ 2022 ~ 2027
MySQL报错1040Too many connections的原因以及解决方案
MySQL 66 questions, 20000 words + 50 pictures in detail! Necessary for review
1553B environment construction
spark源码阅读总纲
Chen Yu (Aqua) - Safety - & gt; Cloud Security - & gt; Multicloud security
盲盒NFT数字藏品平台系统开发(搭建源码)
Hardware development notes (9): basic process of hardware development, making a USB to RS232 module (8): create asm1117-3.3v package library and associate principle graphic devices