簡介
- LiveData是JetPack提供的一種響應式編程組件姊扔,它可以包含任何數(shù)據(jù)類型的數(shù)據(jù)(String赤套,Int渠脉,Boolean等)存皂。
- LiveData在數(shù)據(jù)發(fā)生變化的時候,會通知給觀察者程奠。
- 一般情況下丈牢,LiveData與ViewModel配合使用的,在這個前提下瞄沙,LiveData都是在ViewModel中聲明的己沛。但是也是可以單獨進行聲明使用的慌核。
- LiveData是具有生命感知的,它的數(shù)據(jù)源一般都是ViewModel提供的申尼,這樣當數(shù)據(jù)源發(fā)生變化我們通過LiveData可以通知給觀察者垮卓。(通常我們的觀察者是組冊在Activity或者Fragment中的)
- 當然也不能忽略生命周期感知這個提點,可以這樣理解师幕,當觀察者處于Active狀態(tài)的時候粟按,LiveData發(fā)生變化觀察者可以收到,但是觀察者處于Paused或者Destoryed狀態(tài)霹粥,那么觀察者就不能收到LiveData的通知了
- 在MVVM中灭将,我們可以使用LiveData幫助ViewModel向Activity或者Fragment進行通信
- 因為ViewModel的生命周期都要比Activity要長的,所以我們不能讓ViewModel持有Activity的引用后控,如果這時我們能在Activity中觀察ViewModel中的LiveData庙曙,那么就不回因為ViewModel持有activity而造成的內(nèi)存泄漏問題。
- LiveData是一個抽象類浩淘,其中我們常用的是它的實現(xiàn)子類 MutableLiveData捌朴,它是一個可變的LievData,主要有如下幾個操作api
- getValue():用于從LiveData中獲取到包裝的數(shù)據(jù)
- setValue():用于給LiveData設(shè)置數(shù)據(jù)
- postValue():同樣也是給LiveData設(shè)置數(shù)據(jù)
- postValue與setValuede 區(qū)別
- setValue():只能作用于UI線程中,如果在工作線程中使用张抄,會發(fā)生crash
- postValue:可以用于工作線程中(非UI線程 )男旗,當然在UI線程中也是可用的。
使用
基本使用
我們知道在MVVM中ViewModel是作為數(shù)據(jù)的持有者欣鳖,而Activity或者Fragment是作為UI的載體(PhoneWindwo),在MVVM中我們一般是使用DataBinding茴厉,將XML文件自動編譯成一個XXXDataBinding的文件泽台,通過在Activity中,用這個XXDataBinding去綁定我們的數(shù)據(jù)持有者ViewModel矾缓,然后在xml引入這個ViewModel怀酷,并且去動態(tài)綁定我們ViewModel中的LiveData或者Observable。達到一個數(shù)據(jù)監(jiān)聽的作用嗜闻。
場景設(shè)定:我們有一個ViewModel蜕依,內(nèi)部有一個LiveData包裝著String類型,同時在Activity中獲取到這個ViewModel琉雳,注冊一個觀察者去監(jiān)聽ViewModel中的LiveData样眠,當我們點擊按鈕設(shè)置一個數(shù)據(jù)源給LiveData,然后在觀察者中去更新xml文件中的一個text翠肘。
-
代碼實現(xiàn)如下
class LiveDataMainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_live_data_main) //獲取到ViewModel(此種方式獲取ViewModel要在Lifecycle2.2.0之后喲i苁) var viewModelDemo2 = ViewModelProvider(this)[ViewModelDemo2::class.java] //注冊一個觀察者,用于觀察LiveData束倍,當LiveData的數(shù)據(jù)源發(fā)生改變會通知到觀察者中 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實則是調(diào)用了Transformations#map()方法被丧,通過該方法可以將我們的LiveData進行數(shù)據(jù)類型轉(zhuǎn)換成新類型的LiveData,然后在Activity中注冊新LiveData的觀察者就能拿到數(shù)據(jù)源了盟戏,
說的可能比較抽象,以列子來說明吧
場景設(shè)定:有一個Person甥桂,包含姓名和性別柿究,但是我們的UI控件上只用來顯示姓名的,這時我們可以通過map這種方式來做處理
-
代碼實現(xiàn)如下
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轉(zhuǎn)換成一個新的LiveData * 第一個參數(shù)是我們要進行轉(zhuǎn)化的LiveData黄选。里面包裝了我們需要的數(shù)據(jù) * 第二個參數(shù)是我們要進行轉(zhuǎn)化的函數(shù) * 這樣當userLiveData的數(shù)據(jù)源發(fā)生變化的時候蝇摸,我們transformLiveData的觀察者就能收到轉(zhuǎn)化后的數(shù)據(jù)源了 */ var transformLiveData = Transformations.map(userLiveData) { it.name } }
switchMap
switchMap同樣是Transformations中的,該方法同樣有兩個參數(shù) 參數(shù)一:LiveData 參數(shù)二:函數(shù)轉(zhuǎn)換體
與map不同糕簿,switchMap的函數(shù)轉(zhuǎn)化中必須要返回一個LiveData對象探入,
參數(shù)一:我們可以作為一個條件決定函數(shù)轉(zhuǎn)化中返回什么類型的LiveData,也可以將其包裝的數(shù)據(jù)作為新的LiveData在轉(zhuǎn)化函數(shù)中返回
場景設(shè)定:同樣有一個Person懂诗,是一個外國人蜂嗽,有firstName和lastName,不過我們有一個條件就是殃恒,UI控件只能顯示lastName或者firstName
-
代碼實現(xiàn)如下
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觀察控件顯示是否發(fā)生變化了呢 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的數(shù)據(jù)源
該操作使用的是MediatorLiveData植旧,它繼承MutableLiveData,在原有功能的基礎(chǔ)上离唐,新增了合并多個LiveData的數(shù)據(jù)源的功能病附,實則就是一個組件監(jiān)聽多個LiveData,通過addSource方法
場景設(shè)定:我們有一個控件亥鬓,和兩個LiveData(L1,L2),當L1的數(shù)據(jù)源發(fā)生變化完沪,我們控件顯示L1的,當L2數(shù)據(jù)源發(fā)生變化實現(xiàn)L2的嵌戈,可能我們的做法就是在ViewModel中聲明兩個LiveData覆积,然后在Activity中分別注冊這兩個LiveData的觀察者,當數(shù)據(jù)源發(fā)生改變?nèi)ジ耈I熟呛,其實我們可以使用MediatorLiveData去簡化這個操作宽档,不用在Activity中注冊兩個LiveData的觀察者
-
代碼實現(xiàn)
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) } } }
總結(jié)
- 主要介紹了一下LiveData的幾種使用場景
- LiveData作為ViewModel和Activity之間的橋梁,具有生命感知庵朝,并且不會存在內(nèi)存泄漏吗冤,其實靠的是Lifecycle組件
- LiveData在內(nèi)部使用了Lifecycle組件,來感知生命周期的變化九府,當Activity銷毀的時候也會釋放掉引用椎瘟,防止內(nèi)存泄漏。
- LiveData的數(shù)據(jù)源發(fā)生變化只會通知到處于Active狀態(tài)的Activity中的觀察者侄旬,當Activty由不可見變?yōu)榭梢姷臓顟B(tài)降传,那么此時觀察者會收到通知,實則為了減少性能損耗嘛
- 當Activity處于不可見狀態(tài)時勾怒,LiveData發(fā)生了多次改變婆排,當變成可見狀態(tài)時只能收到最新的變化通知