又到週末好時光,茫茫人海中,與你在掘金相遇,好幸運~請君賞閱本文,相處不易,開門見山,不扯皮。本文講的是Jetpack系列第三個架構組件LiveData,LiveData是Lifecycle-aware 組件的一個應用,這意味着LiveData遵照Activity、Fragment和Service等組件的生命週期,在它們生命週期處於活躍狀態(CREATED
和RESUMED
)才進行更新Views。java
三個步驟就定義了使用LiveData的方式,從步驟能夠看出,使用了觀察者模式,當LiveData對象持有數據發生變化,會通知對它訂閱的全部處於活躍狀態的訂閱者。而這些訂閱者一般是UI控制器,如Activity或Fragment,以能在被通知時,自動去更新Views。android
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
有了數據源以後,總須要有觀察者來觀察數據源,否則數據源就失去了存在的意義。數據庫
那麼在哪裏觀察數據源呢?設計模式
在大多數狀況下,在應用組件的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的數據的話,能夠經過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。
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,並重寫兩個重要方法。
value=price
這裏是調用了setValue(price)方法,經過該方法更新LiveData的值,進而通知處於活躍狀態的訂閱者。LiveData會認爲訂閱者的生命週期處於STARTED
或RESUMED
狀態時,該訂閱者是活躍的。
那麼如何使用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.
})
}
複製代碼
有時候在把數據分發給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對象,或許這種轉換會是很好的解決方案。
MediatorLiveData是LiveData的子類,它主要用途是用來合併多個LiveData源。當其中一個源數據發生變化是,都會回調訂閱MediatorLiveData的觀察者的onChanged()
方法。例如咱們在實際開發中,咱們的數據源要麼來自服務器,要麼來自本地數據庫。這裏就考慮使用MediatorLiveData。
LiveData的入門使用來講仍是相對簡單的,等到後面講完Jetpack系列文章,再以一個綜合的Demo示例Jetpack涉及到的一些知識點。光看文檔,均可以感受到Android 對設計模式,和MVP模式、MVVM模式設計理念使用得淋漓盡致。因此建議各位同窗在代碼方面的編寫必定要有大局觀念,代碼規範的仍是要有,方便別人就是方便本身。不要爲應付功能實現而代碼臃腫,後續又不從新架構,一直積累成垃圾碼。
本文是Jetpack系列文章第三篇