LiveData的使用介绍

Android_Banner.jpg

简介

  • LiveData是JetPack提供的一种响应式编程组件,它可以包含任何数据类型的数据(String,Int,Boolean等)。
  • LiveData在数据发生变化的时候,会通知给观察者。
  • 一般情况下,LiveData与ViewModel配合使用的,在这个前提下,LiveData都是在ViewModel中声明的。但是也是可以单独进行声明使用的。
    • LiveData是具有生命感知的,它的数据源一般都是ViewModel提供的,这样当数据源发生变化我们通过LiveData可以通知给观察者。(通常我们的观察者是组册在Activity或者Fragment中的)
    • 当然也不能忽略生命周期感知这个提点,可以这样理解,当观察者处于Active状态的时候,LiveData发生变化观察者可以收到,但是观察者处于Paused或者Destoryed状态,那么观察者就不能收到LiveData的通知了
  • 在MVVM中,我们可以使用LiveData帮助ViewModel向Activity或者Fragment进行通信
    • 因为ViewModel的生命周期都要比Activity要长的,所以我们不能让ViewModel持有Activity的引用,如果这时我们能在Activity中观察ViewModel中的LiveData,那么就不回因为ViewModel持有activity而造成的内存泄漏问题。
  • LiveData是一个抽象类,其中我们常用的是它的实现子类 MutableLiveData,它是一个可变的LievData,主要有如下几个操作api
    • getValue():用于从LiveData中获取到包装的数据
    • setValue():用于给LiveData设置数据
    • postValue():同样也是给LiveData设置数据
  • postValue与setValuede 区别
    • setValue():只能作用于UI线程中,如果在工作线程中使用,会发生crash
    • postValue:可以用于工作线程中(非UI线程 ),当然在UI线程中也是可用的。

使用

基本使用

我们知道在MVVM中ViewModel是作为数据的持有者,而Activity或者Fragment是作为UI的载体(PhoneWindwo),在MVVM中我们一般是使用DataBinding,将XML文件自动编译成一个XXXDataBinding的文件,通过在Activity中,用这个XXDataBinding去绑定我们的数据持有者ViewModel,然后在xml引入这个ViewModel,并且去动态绑定我们ViewModel中的LiveData或者Observable。达到一个数据监听的作用。

  • 场景设定:我们有一个ViewModel,内部有一个LiveData包装着String类型,同时在Activity中获取到这个ViewModel,注册一个观察者去监听ViewModel中的LiveData,当我们点击按钮设置一个数据源给LiveData,然后在观察者中去更新xml文件中的一个text。

  • 代码实现如下

    class LiveDataMainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_live_data_main)
            //获取到ViewModel(此种方式获取ViewModel要在Lifecycle2.2.0之后哟!)
            var viewModelDemo2 = ViewModelProvider(this)[ViewModelDemo2::class.java]
            //注册一个观察者,用于观察LiveData,当LiveData的数据源发生改变会通知到观察者中
            viewModelDemo2.liveData.observe(this, Observer {
                it?.let { value ->
                    tvText.text = value
                }
    
            })
    
            btnChange.setOnClickListener {
                viewModelDemo2.liveData.postValue("i am coming ")
    
            }
    
    
        }
    }
    
    class ViewModelDemo2 : ViewModel() {
    
        var liveData = MutableLiveData<String>()
    }
    
map

这里说的map实则是调用了Transformations#map()方法,通过该方法可以将我们的LiveData进行数据类型转换成新类型的LiveData,然后在Activity中注册新LiveData的观察者就能拿到数据源了,

说的可能比较抽象,以列子来说明吧

  • 场景设定:有一个Person,包含姓名和性别,但是我们的UI控件上只用来显示姓名的,这时我们可以通过map这种方式来做处理

  • 代码实现如下

    class MapLiveDataMainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_map_live_data_main)
            var viewModel = ViewModelProvider(this)[MapLiveDataViewModel::class.java]
            var person = Person()
            person.name = "DashingQi"
            person.sex = "man"
    
            viewModel.transformLiveData.observe(this, Observer {
                it?.let { value ->
                    tvText.text = value
                }
    
            })
            setUser.setOnClickListener {
                viewModel.userLiveData.postValue(person)
            }
    
    
        }
    }
    
    class MapLiveDataViewModel : ViewModel() {
    
        var userLiveData = MutableLiveData<Person>()
    
        /**
         * 使用Transformations#map转换成一个新的LiveData
         * 第一个参数是我们要进行转化的LiveData。里面包装了我们需要的数据
         * 第二个参数是我们要进行转化的函数
         * 这样当userLiveData的数据源发生变化的时候,我们transformLiveData的观察者就能收到转化后的数据源了
         */
        var transformLiveData = Transformations.map(userLiveData) {
            it.name
        }
    }
    
switchMap

switchMap同样是Transformations中的,该方法同样有两个参数 参数一:LiveData 参数二:函数转换体

与map不同,switchMap的函数转化中必须要返回一个LiveData对象,

参数一:我们可以作为一个条件决定函数转化中返回什么类型的LiveData,也可以将其包装的数据作为新的LiveData在转化函数中返回

  • 场景设定:同样有一个Person,是一个外国人,有firstName和lastName,不过我们有一个条件就是,UI控件只能显示lastName或者firstName

  • 代码实现如下

    class SwitMapMainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_swit_map_main)
            var switchMapViewModel = ViewModelProvider(this)[SwitchMapViewModel::class.java]
            switchMapViewModel.transformationsLiveData.observe(this, Observer {
                it.let { value ->
                    nameText.text = value
                }
    
            })
    
            setUser.setOnClickListener {
                var person = Person()
                person.firstName = "zhang"
                person.lastName = "qi"
                //当切换 true或者false观察控件显示是否发生变化了呢
                person.condition = false
                switchMapViewModel.conditionLiveData.postValue(person)
            }
        }
    }
    class SwitchMapViewModel:ViewModel() {
    
        var conditionLiveData = MutableLiveData<Person>()
    
        val transformationsLiveData = Transformations.switchMap(conditionLiveData){
             if (it.condition){
                MutableLiveData(it.firstName)
            }else{
               MutableLiveData(it.lastName)
           }
        }
    }
    class Person {
        var name = ""
        var sex = ""
        var firstName = ""
        var lastName = ""
        var condition = false
    }
    
合并多个LiveData的数据源

该操作使用的是MediatorLiveData,它继承MutableLiveData,在原有功能的基础上,新增了合并多个LiveData的数据源的功能,实则就是一个组件监听多个LiveData,通过addSource方法

  • 场景设定:我们有一个控件,和两个LiveData(L1,L2),当L1的数据源发生变化,我们控件显示L1的,当L2数据源发生变化实现L2的,可能我们的做法就是在ViewModel中声明两个LiveData,然后在Activity中分别注册这两个LiveData的观察者,当数据源发生改变去更新UI,其实我们可以使用MediatorLiveData去简化这个操作,不用在Activity中注册两个LiveData的观察者

  • 代码实现

    class MediatorLiveDataMainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_mediator_live_data_main)
            var mediatorLiveDataViewModel =
                ViewModelProvider(this)[MediatorLiveDataViewModel::class.java]
            mediatorLiveDataViewModel.mediatorLiveData.observe(this, Observer {
                text.text = it
            })
    
            setLiveData1.setOnClickListener {
                mediatorLiveDataViewModel.liveData1.postValue("liveData1")
            }
    
            setLiveData2.setOnClickListener {
                mediatorLiveDataViewModel.liveData2.postValue("liveData2")
            }
        }
    }
    class MediatorLiveDataViewModel : ViewModel() {
        var liveData1 = MutableLiveData<String>()
        var liveData2 = MutableLiveData<String>()
    
        var mediatorLiveData = MediatorLiveData<String>()
    
    
        init {
            mediatorLiveData.addSource(liveData1) {
                Log.d("perform livedata1", it)
                mediatorLiveData.postValue(it)
            }
    
            mediatorLiveData.addSource(liveData2) {
                Log.d("perform livedata2", it)
                mediatorLiveData.postValue(it)
            }
        }
    }
    

总结

  • 主要介绍了一下LiveData的几种使用场景
  • LiveData作为ViewModel和Activity之间的桥梁,具有生命感知,并且不会存在内存泄漏,其实靠的是Lifecycle组件
  • LiveData在内部使用了Lifecycle组件,来感知生命周期的变化,当Activity销毁的时候也会释放掉引用,防止内存泄漏。
  • LiveData的数据源发生变化只会通知到处于Active状态的Activity中的观察者,当Activty由不可见变为可见的状态,那么此时观察者会收到通知,实则为了减少性能损耗嘛
    • 当Activity处于不可见状态时,LiveData发生了多次改变,当变成可见状态时只能收到最新的变化通知
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。