Jetpack:LiveData入門指南

又到週末好時光,茫茫人海中,與你在掘金相遇,好幸運~請君賞閱本文,相處不易,開門見山,不扯皮。本文講的是Jetpack系列第三個架構組件LiveData,LiveData是Lifecycle-aware 組件的一個應用,這意味着LiveData遵照Activity、Fragment和Service等組件的生命週期,在它們生命週期處於活躍狀態(CREATEDRESUMED)才進行更新Views。java

使用LiveData步驟

  1. 建立持有某種類型的LiveData對象。一般在ViewModel類來實現該對象。
  2. 定義一個具備onChanged()方法的Observer對象,當LiveData持有數據變化是回調該方法。一般在UI控制器類中實現建立該Observer對象,如Activity或Fragment。
  3. 經過使用observe()方法,將上述的LiveData對象和Observer對象關聯在一塊兒。這樣Observer對象就與LiveData產生了訂閱關係,當LiveData數據發生變化時通知,而在Observer更新數據,因此Observer一般是Activity和Fragment。

三個步驟就定義了使用LiveData的方式,從步驟能夠看出,使用了觀察者模式,當LiveData對象持有數據發生變化,會通知對它訂閱的全部處於活躍狀態的訂閱者。而這些訂閱者一般是UI控制器,如Activity或Fragment,以能在被通知時,自動去更新Views。android

建立LiveData對象

LiveData能夠包裝任何數據,包括集合對象。LiveData一般存儲在ViewModel中,並經過getter方法得到。示例:git

class NameViewModel : ViewModel() {

    // Create a LiveData with a String
    val currentName: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

    // Rest of the ViewModel...
}
複製代碼

爲何是ViewModel持有LiveData而不是Activity或者Fragment中呢?github

  • 這樣致使Activity或Fragment代碼臃腫,Activity或Fragment通常用來展現數據而不是持有數據。
  • 將LiveData解耦,不和特定的Activity或Fragment綁定在一塊兒。

建立 觀察LiveData 的對象

有了數據源以後,總須要有觀察者來觀察數據源,否則數據源就失去了存在的意義。數據庫

那麼在哪裏觀察數據源呢?設計模式

在大多數狀況下,在應用組件的onCreate()方法中訪問LiveData是個合適的時機。這樣能夠確保系統不在Activity或Fragment的onResume()方法進行多餘的調用;另外這樣也確保Activity和Fragment儘早有數據能夠進行顯示。bash

class NameActivity : AppCompatActivity() {

    private lateinit var model: NameViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Other code to setup the activity...

        // Get the ViewModel.
        model = ViewModelProviders.of(this).get(NameViewModel::class.java)


        // Create the observer which updates the UI.
        val nameObserver = Observer<String> { newName ->
            // Update the UI, in this case, a TextView. 
            nameTextView.text = newName
        }

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        model.currentName.observe(this, nameObserver)
    }
}
複製代碼

在講nameObserver對象傳給observe()方法後,存儲在LiveData最近的值以參數的形式當即傳遞到onChange()方法中。固然,若是此時LiveData沒有存儲值的話,onChange()方法不會被調用。服務器

更新 LiveData 對象

LiveData自己沒有提供公共方法更新值。若是須要修改LiveData的數據的話,能夠經過MutableLiveData來暴露共有方法setValue()postValue()。一般在在ViewModel中使用MutableLiveData,而MutableLiveData暴露不可變的LiveData給Observer。與Observer創建關係後,經過修改LiveData的值從而更新Observer中的視圖。網絡

button.setOnClickListener {
    val anotherName = "GitCode"
    model.currentName.setValue(anotherName)
}
複製代碼

當單擊button時,字符串GitCode會存儲到LiveData中,nameTextView的文本也會更新爲GitCode。這裏經過button的點擊來給LiveData設置值,也能夠網絡或者本地數據庫獲取數據方式來設置值。架構

擴展 LiveData

能夠經過下面的栗子來看看如何擴展LiveData。

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)
    }
}
複製代碼

首先創建一個StockLiveData並繼承自LiveData,並重寫兩個重要方法。

  • onActivite() 當有活躍狀態的訂閱者訂閱LiveData時會回調該方法。意味着須要在這裏監聽數據的變化。
  • onInactive() 當沒有活躍狀態的訂閱者訂閱LiveData時會回調該方法。此時沒有必要保持StockManage服務象的鏈接。
  • setValue() 注意到value=price這裏是調用了setValue(price)方法,經過該方法更新LiveData的值,進而通知處於活躍狀態的訂閱者。

LiveData會認爲訂閱者的生命週期處於STARTEDRESUMED狀態時,該訂閱者是活躍的。

那麼如何使用StockLiveData呢?

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    val myPriceListener: LiveData<BigDecimal> = ...
    myPriceListener.observe(this, Observer<BigDecimal> { price: BigDecimal? ->
        // Update the UI.
    })
}
複製代碼

以Fragment做LifecycleOwner的實例傳遞到observer()方法中,這樣就將Observer綁定到擁有生命週期的擁有者。因爲LiveData能夠在多個Activity、Fragment和Service中使用,因此能夠建立單例模式。

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.
        })

    }
複製代碼

轉換 LiveData

有時候在把數據分發給Observer前,轉換存儲在LiveData中的值,或者返回一個 基於已有值的LiveData對象 的另一個LiveData對象。這時候就須要用到 Transformations類來處理了。

使用Transformations.map()方法能夠改變其下游的結果:

LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
    user.name + " " + user.lastName
});
複製代碼

使用Transformations.switchMap()一樣能夠改變下游的結果,但傳遞給switchMap()的函數必須返回一個LiveData對象。

private fun getUser(id: String): LiveData<User> {
  ...
}
val userId: LiveData<String> = ...
val user = Transformations.switchMap(userId) { id -> getUser(id) }
複製代碼

這種轉換方式都惰性的,也就是隻有Observer來訂閱數據的時候,纔會進行轉換。當在ViewModel須要一個Lifecycle對象,或許這種轉換會是很好的解決方案。

合併多個LiveData 源

MediatorLiveData是LiveData的子類,它主要用途是用來合併多個LiveData源。當其中一個源數據發生變化是,都會回調訂閱MediatorLiveData的觀察者的onChanged()方法。例如咱們在實際開發中,咱們的數據源要麼來自服務器,要麼來自本地數據庫。這裏就考慮使用MediatorLiveData。

更多信息請參閱官網

總結

LiveData的入門使用來講仍是相對簡單的,等到後面講完Jetpack系列文章,再以一個綜合的Demo示例Jetpack涉及到的一些知識點。光看文檔,均可以感受到Android 對設計模式,和MVP模式、MVVM模式設計理念使用得淋漓盡致。因此建議各位同窗在代碼方面的編寫必定要有大局觀念,代碼規範的仍是要有,方便別人就是方便本身。不要爲應付功能實現而代碼臃腫,後續又不從新架構,一直積累成垃圾碼。

Welcom to visit my github

本文是Jetpack系列文章第三篇

第一篇: Jetpack:你還在findViewById麼?

第二篇:Jetpack:你如何管理Activity和Fragment的生命週期?

相關文章
相關標籤/搜索