LiveData的使用介紹

Android_Banner.jpg

簡介

  • 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)時只能收到最新的變化通知
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末声旺,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子段只,更是在濱河造成了極大的恐慌腮猖,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赞枕,死亡現(xiàn)場離奇詭異澈缺,居然都是意外死亡,警方通過查閱死者的電腦和手機炕婶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門姐赡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人柠掂,你說我怎么就攤上這事项滑。” “怎么了涯贞?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵枪狂,是天一觀的道長。 經(jīng)常有香客問我宋渔,道長州疾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任皇拣,我火速辦了婚禮严蓖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘氧急。我一直安慰自己谈飒,他們只是感情好,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布态蒂。 她就那樣靜靜地躺著,像睡著了一般费什。 火紅的嫁衣襯著肌膚如雪钾恢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天鸳址,我揣著相機與錄音瘩蚪,去河邊找鬼。 笑死稿黍,一個胖子當著我的面吹牛疹瘦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播巡球,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼言沐,長吁一口氣:“原來是場噩夢啊……” “哼邓嘹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起险胰,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤汹押,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后起便,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體棚贾,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年榆综,在試婚紗的時候發(fā)現(xiàn)自己被綠了妙痹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡鼻疮,死狀恐怖怯伊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情陋守,我是刑警寧澤震贵,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站水评,受9級特大地震影響猩系,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜中燥,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一寇甸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧疗涉,春花似錦拿霉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至闹伪,卻和暖如春沪铭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背偏瓤。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工杀怠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人厅克。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓赔退,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子硕旗,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354