Android Jetpack架構(gòu)組件-LiveData使用

谷歌推出的LiveData和RxJava類似洽瞬,也是基于觀察者本涕,你可以認(rèn)為LiveData是輕量級的RxJava。起初LiveData并不被看好片任,隨著谷歌的大力推廣偏友,LiveData也慢慢的進(jìn)入了大家的視野蔬胯。一般來說对供,LiveData很少單獨(dú)使用,它更多的和Android
Jetpack的其他組件搭配使用氛濒,比如和ViewModel产场、Room、Paging等舞竿。這篇文章就來介紹LiveData的使用京景。

一、定義

LiveData 是一種可觀察的數(shù)據(jù)存儲器類骗奖。與常規(guī)的可觀察類不同确徙,LiveData 具有生命周期感知能力,意指它遵循其他應(yīng)用組件(如 Activity执桌、Fragment 或 Service)的生命周期鄙皇。這種感知能力可確保 LiveData 僅更新處于活躍生命周期狀態(tài)的應(yīng)用組件觀察者。

二仰挣、優(yōu)勢:

使用 LiveData 具有以下優(yōu)勢:

  • 確保界面符合數(shù)據(jù)狀態(tài)

    LiveData 遵循觀察者模式伴逸。當(dāng)生命周期狀態(tài)發(fā)生變化時,LiveData 會通知 Observer 對象膘壶。您可以整合代碼以在這些 Observer 對象中更新界面错蝴。觀察者可以在每次發(fā)生更改時更新界面洲愤,而不是在每次應(yīng)用數(shù)據(jù)發(fā)生更改時更新界面。

  • 不會發(fā)生內(nèi)存泄露

    觀察者會綁定到 Lifecycle 對象顷锰,并在其關(guān)聯(lián)的生命周期遭到銷毀后進(jìn)行自我清理柬赐。

  • 不會因 Activity 停止而導(dǎo)致崩潰

    如果觀察者的生命周期處于非活躍狀態(tài)(如返回棧中的 Activity),則它不會接收任何 LiveData 事件官紫。

  • 不再需要手動處理生命周期

    界面組件只是觀察相關(guān)數(shù)據(jù)躺率,不會停止或恢復(fù)觀察。LiveData 將自動管理所有這些操作万矾,因為它在觀察時可以感知相關(guān)的生命周期狀態(tài)變化悼吱。

  • 數(shù)據(jù)始終保持最新狀態(tài)

    如果生命周期變?yōu)榉腔钴S狀態(tài),它會在再次變?yōu)榛钴S狀態(tài)時接收最新的數(shù)據(jù)良狈。例如后添,曾經(jīng)在后臺的 Activity 會在返回前臺后立即接收最新的數(shù)據(jù)。

  • 適當(dāng)?shù)呐渲酶?/strong>

    如果由于配置更改(如設(shè)備旋轉(zhuǎn))而重新創(chuàng)建了 Activity 或 Fragment薪丁,它會立即接收最新的可用數(shù)據(jù)遇西。

  • 共享資源

    您可以使用單一實例模式擴(kuò)展 LiveData 對象以封裝系統(tǒng)服務(wù),以便在應(yīng)用中共享它們严嗜。LiveData 對象連接到系統(tǒng)服務(wù)一次粱檀,然后需要相應(yīng)資源的任何觀察者只需觀察 LiveData 對象,后文都會提高

三漫玄、使用liveData

LiveData的數(shù)據(jù)源一般是ViewModel茄蚯,也可以是其它可以更新LiveData的組件。當(dāng)數(shù)據(jù)更新后睦优,LiveData 就會通知它的所有觀察者渗常,比如Activiy。

與RxJava的方法不同的是汗盘,LiveData并不是通知所有觀察者皱碘,它只會通知處于Active狀態(tài)的觀察者,如果一個觀察者處于Paused或Destroyed狀態(tài)隐孽,它將不會收到通知癌椿。

這對于Activiy和Service特別有用,因為它們可以安全地觀察LiveData對象而不用擔(dān)心內(nèi)存泄漏的問題菱阵。開發(fā)者也不需要在onPause或onDestroy方法中解除對LiveData的訂閱踢俄。還有一點(diǎn)需要注意的是一旦觀察者重新恢復(fù)Resumed狀態(tài),它將會重新收到LiveData的最新數(shù)據(jù)送粱。

3.1褪贵、 LiveData的基本使用

示例為Button事件點(diǎn)擊,LiveData發(fā)送個數(shù)據(jù),觀察者接收到數(shù)據(jù)更新以后更新UI

class LiveDataActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)

        var liveData: LiveData<String> = MutableLiveData<String>()

        btn_ald_post.setOnClickListener {
             //發(fā)送數(shù)據(jù)
            (liveData as MutableLiveData).postValue("有新消息了")
        }

        //觀察livedata對象
        liveData.observe(this, Observer<String> {
            //Updata UI
            tv_ald_info.text = it
        })
    }
}

liveData.observe(this脆丁,Observer<String>)方法有兩個參數(shù)分別是LifecycleOwnerObserver 世舰,第一個參數(shù)就是LiveDataActivity本身,因為父類已實現(xiàn)了LifecycleOwner接口,詳情可參考筆者Lifecycle的文章槽卫,第二個參數(shù)則新建了一個Observer跟压,在onChanged方法中得到回調(diào)。注釋處的postValue方法會在主線程中更新數(shù)據(jù)歼培,這樣就會更改TextView中text屬性的值震蒋。

在大多數(shù)情況下,LiveData的observe方法會放在onCreate方法中躲庄,如果放在onResume方法中查剖,會出現(xiàn)多次調(diào)用的問題。除了MutableLiveData的postValue方法噪窘,還可以使用setValue方法笋庄,它們之前的區(qū)別是,setValue方法必須在主線程使用倔监,如果是在工作線程中更新LiveData直砂,則可以使用postValue方法。

3.2浩习、 更改LiveData中的數(shù)據(jù)

如果我們想要在LiveData對象分發(fā)給觀察者之前對其中存儲的值進(jìn)行更改静暂,可以使用Transformations.map()Transformations.switchMap(),類似于Rxjava中的map()方法
下面通過簡單的例子來講解它們

        var liveData: LiveData<String> = MutableLiveData<String>()

        btn_ald_post.setOnClickListener {
            (liveData as MutableLiveData).postValue("有新消息了")
        }

        var changLiveData = Transformations.map(liveData) {
            it + "changed"
        }

        changLiveData.observe(this, Observer<String> {
            tv_ald_info.text = it
        })

運(yùn)行結(jié)果為TextView的值為

"有新消息changed"

3.3谱秽、 Transformations.switchMap()

如果想要手動控制監(jiān)聽其中一個的數(shù)據(jù)變化洽蛀,并能根據(jù)需要隨時切換監(jiān)聽,這時可以使用Transformations.switchMap()弯院,它和Transformations.map()使用方式類似辱士,只不過switchMap()必須返回一個LiveData對象。

MediatorLiveDataLiveData 的子類听绳,允許您合并多個 LiveData 源。只要任何原始的 LiveData 源對象發(fā)生更改异赫,就會觸發(fā) MediatorLiveData 對象的觀察者椅挣。

例如,如果界面中有可以從本地數(shù)據(jù)庫或網(wǎng)絡(luò)更新的 LiveData 對象塔拳,則可以向 MediatorLiveData 對象添加以下源:

  • 與存儲在數(shù)據(jù)庫中的數(shù)據(jù)關(guān)聯(lián)的 LiveData 對象鼠证。
  • 與從網(wǎng)絡(luò)訪問的數(shù)據(jù)關(guān)聯(lián)的 LiveData 對象。
    ?
    代碼如下所示:
class MergerLiveDataActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_merger)
        
        val mutableLiveData1 = MutableLiveData<String>()
        val mutableLiveData2 = MutableLiveData<String>()
        val mutableLiveData3 = MutableLiveData<String>()
        val liveDataMerger: MediatorLiveData<*> = MediatorLiveData<String>()
        
        liveDataMerger.addSource(mutableLiveData1, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.d("TAG", "onChanged1:$t")
            }
        })

        liveDataMerger.addSource(mutableLiveData2, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.d("TAG", "onChanged2:$t")
            }
        })
        
        liveDataMerger.addSource(mutableLiveData3, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.d("TAG", "onChanged3:$t")
            }
        })
        
        liveDataMerger.observe(this, Observer {
            Log.d("TAG", "onChanged:$it");
        })
        

        mutableLiveData1.postValue("Onexzgj 的Jetpack")
        mutableLiveData2.postValue("Onexzgj 的Jetpack2")
        mutableLiveData3.postValue("Onexzgj 的Jetpack3")
    }
}

為了更直觀的舉例靠抑,將LiveData和MediatorLiveData放到了同一個Activity中量九。通過MediatorLiveData的addSource將兩個MutableLiveData合并到一起,這樣當(dāng)任何一個MutableLiveData數(shù)據(jù)發(fā)生變化時,MediatorLiveData都可以感知到荠列。

打印結(jié)果如下类浪,任何一個liveData發(fā)生變化,liveDataMerger都會接受到通知

截屏2020-03-2512.10.32.png

3.4肌似、擴(kuò)展LiveData對象

如果觀察者的生命周期出于STARTED或者RESUMED狀態(tài)费就,LiveData會將觀察者視為處于Active狀態(tài),關(guān)于如何擴(kuò)展LiveData,官網(wǎng)的例子比較簡潔川队,如下所示:

    class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
        private val stockManager = StockManager(symbol)

        private val listener = { price: BigDecimal ->
            value = price
        }

        override fun onActive() {
            stockManager.requestPriceUpdates(listener)
        }

        override fun onInactive() {
            stockManager.removeUpdates(listener)
        }
    }

上面的代碼是一個觀察股票變動的一個例子力细,對LiveData進(jìn)行了拓展,實現(xiàn)了LiveData的兩個空方法onActive和onInactive固额。當(dāng)Active狀態(tài)的觀察者的數(shù)量從0變?yōu)?時會調(diào)用onActive方法眠蚂,通俗來講,就是當(dāng)LiveData對象具有Active狀態(tài)的觀察者時調(diào)用onActive方法斗躏,應(yīng)該在onActive方法中開始觀察股票價格的更新河狐。當(dāng)LiveData對象沒有任何Active狀態(tài)的觀察者時調(diào)用onInactive方法,在這個方法中瑟捣,斷開與StockManager服務(wù)的連接馋艺。

LiveData 對象具有生命周期感知能力,這一事實意味著您可以在多個 Activity迈套、Fragment 和 Service 之間共享它們捐祠。為使示例保持簡單,所以可以將 LiveData 類實現(xiàn)為單一實例桑李,如下所示:

 class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
        private val stockManager: StockManager = StockManager(symbol)

        private val listener = { price: BigDecimal ->
            value = price
        }

        override fun onActive() {
            stockManager.requestPriceUpdates(listener)
        }

        override fun onInactive() {
            stockManager.removeUpdates(listener)
        }

        companion object {
            private lateinit var sInstance: StockLiveData

            @MainThread
            fun get(symbol: String): StockLiveData {
                sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
                return sInstance
            }
        }
    }

因此在Fragment中使用如下所示:

    class MyFragment : Fragment() {
        override fun onActivityCreated(savedInstanceState: Bundle?) {
            StockLiveData.get(symbol).observe(this, Observer<BigDecimal> { price: BigDecimal? ->
                // Update the UI.
            })
        }

多個 Fragment 和 Activity 可以觀察 MyPriceListener 實例踱蛀。僅當(dāng)一個或多個系統(tǒng)服務(wù)可見且處于活躍狀態(tài)時,LiveData 才會連接到該服務(wù)贵白。

四率拒、總結(jié)

這篇文章主要介紹了什么是LiveData,簡而言之可以理解為RxBus,以及LiveData的使用方法禁荒,這里沒有介紹LiveDataViewModel的結(jié)合使用猬膨,以及LiveData的原理,這些會在后面的文章進(jìn)行介紹呛伴。

最后文章中涉及到的源碼及Jetpack的全組件均上傳至OnexZgj/Jetpack_Component

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末勃痴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子热康,更是在濱河造成了極大的恐慌沛申,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姐军,死亡現(xiàn)場離奇詭異铁材,居然都是意外死亡尖淘,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門著觉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來村生,“玉大人,你說我怎么就攤上這事固惯“鹪欤” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵葬毫,是天一觀的道長镇辉。 經(jīng)常有香客問我,道長贴捡,這世上最難降的妖魔是什么忽肛? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮烂斋,結(jié)果婚禮上屹逛,老公的妹妹穿的比我還像新娘。我一直安慰自己汛骂,他們只是感情好罕模,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著帘瞭,像睡著了一般淑掌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蝶念,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天抛腕,我揣著相機(jī)與錄音,去河邊找鬼媒殉。 笑死担敌,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的廷蓉。 我是一名探鬼主播全封,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼苦酱!你這毒婦竟也來了售貌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤疫萤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后敢伸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扯饶,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了尾序。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钓丰。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖每币,靈堂內(nèi)的尸體忽然破棺而出携丁,到底是詐尸還是另有隱情,我是刑警寧澤兰怠,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布梦鉴,位于F島的核電站,受9級特大地震影響揭保,放射性物質(zhì)發(fā)生泄漏肥橙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一秸侣、第九天 我趴在偏房一處隱蔽的房頂上張望存筏。 院中可真熱鬧,春花似錦味榛、人聲如沸椭坚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至继榆,卻和暖如春巾表,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背略吨。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工集币, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人翠忠。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓鞠苟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親秽之。 傳聞我的和親對象是個殘疾皇子当娱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容