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发生了多次改变,当变成可见状态时只能收到最新的变化通知
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352