目錄
谷歌推出的LiveData和RxJava類似,也是基於觀察者,你可以認爲LiveData是輕量級的RxJava。起初LiveData並不被看好,隨着谷歌的大力推廣,LiveData也慢慢的進入了大家的視野。一般來說,LiveData很少單獨使用,它更多的和Android
Jetpack的其他組件搭配使用,比如和ViewModel、Room、Paging等。這篇文章就來介紹LiveData的使用。
一、定義
LiveData
是一種可觀察的數據存儲器類。與常規的可觀察類不同,LiveData 具有生命週期感知能力,意指它遵循其他應用組件(如 Activity、Fragment 或 Service)的生命週期。這種感知能力可確保 LiveData 僅更新處於活躍生命週期狀態的應用組件觀察者。
二、優勢:
使用 LiveData 具有以下優勢:
-
確保界面符合數據狀態
LiveData 遵循觀察者模式。當生命週期狀態發生變化時,LiveData 會通知
Observer
對象。您可以整合代碼以在這些Observer
對象中更新界面。觀察者可以在每次發生更改時更新界面,而不是在每次應用數據發生更改時更新界面。 -
不會發生內存泄露
觀察者會綁定到
Lifecycle
對象,並在其關聯的生命週期遭到銷燬後進行自我清理。 -
不會因 Activity 停止而導致崩潰
如果觀察者的生命週期處於非活躍狀態(如返回棧中的 Activity),則它不會接收任何 LiveData 事件。
-
不再需要手動處理生命週期
界面組件只是觀察相關數據,不會停止或恢復觀察。LiveData 將自動管理所有這些操作,因爲它在觀察時可以感知相關的生命週期狀態變化。
-
數據始終保持最新狀態
如果生命週期變爲非活躍狀態,它會在再次變爲活躍狀態時接收最新的數據。例如,曾經在後臺的 Activity 會在返回前臺後立即接收最新的數據。
-
適當的配置更改
如果由於配置更改(如設備旋轉)而重新創建了 Activity 或 Fragment,它會立即接收最新的可用數據。
-
共享資源
您可以使用單一實例模式擴展
LiveData
對象以封裝系統服務,以便在應用中共享它們。LiveData
對象連接到系統服務一次,然後需要相應資源的任何觀察者只需觀察LiveData
對象,後文都會提高
三、使用liveData
LiveData的數據源一般是ViewModel,也可以是其它可以更新LiveData的組件。當數據更新後,LiveData 就會通知它的所有觀察者,比如Activiy。
與RxJava的方法不同的是,LiveData並不是通知所有觀察者,它只會通知處於Active狀態的觀察者,如果一個觀察者處於Paused或Destroyed狀態,它將不會收到通知。
這對於Activiy和Service特別有用,因爲它們可以安全地觀察LiveData對象而不用擔心內存泄漏的問題。開發者也不需要在onPause或onDestroy方法中解除對LiveData的訂閱。還有一點需要注意的是一旦觀察者重新恢復Resumed狀態,它將會重新收到LiveData的最新數據。
3.1、 LiveData的基本使用
示例爲Button事件點擊,LiveData發送個數據,觀察者接收到數據更新以後更新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 {
//發送數據
(liveData as MutableLiveData).postValue("有新消息了")
}
//觀察livedata對象
liveData.observe(this, Observer<String> {
//Updata UI
tv_ald_info.text = it
})
}
}
liveData.observe(this,Observer)方法有兩個參數分別是LifecycleOwner
和 Observer
,第一個參數就是LiveDataActivity本身,因爲父類已實現了LifecycleOwner接口,詳情可參考筆者Lifecycle的文章,第二個參數則新建了一個Observer
,在onChanged方法中得到回調。註釋處的postValue方法會在主線程中更新數據,這樣就會更改TextView中text屬性的值。
在大多數情況下,LiveData的observe方法會放在onCreate方法中,如果放在onResume方法中,會出現多次調用的問題。除了MutableLiveData的postValue方法,還可以使用setValue方法,它們之前的區別是,setValue方法必須在主線程使用,如果是在工作線程中更新LiveData,則可以使用postValue方法。
3.2、 更改LiveData中的數據
如果我們想要在LiveData對象分發給觀察者之前對其中存儲的值進行更改,可以使用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
})
運行結果爲TextView的值爲
"有新消息changed"
3.3、 Transformations.switchMap()
如果想要手動控制監聽其中一個的數據變化,並能根據需要隨時切換監聽,這時可以使用Transformations.switchMap(),它和Transformations.map()使用方式類似,只不過switchMap()必須返回一個LiveData對象。
MediatorLiveData
是 LiveData
的子類,允許您合併多個 LiveData 源。只要任何原始的 LiveData 源對象發生更改,就會觸發 MediatorLiveData
對象的觀察者。
例如,如果界面中有可以從本地數據庫或網絡更新的 LiveData
對象,則可以向 MediatorLiveData
對象添加以下源:
- 與存儲在數據庫中的數據關聯的
LiveData
對象。 - 與從網絡訪問的數據關聯的
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合併到一起,這樣當任何一個MutableLiveData數據發生變化時,MediatorLiveData都可以感知到。
打印結果如下,任何一個liveData發生變化,liveDataMerger都會接受到通知
3.4、擴展LiveData對象
如果觀察者的生命週期出於STARTED或者RESUMED狀態,LiveData會將觀察者視爲處於Active狀態,關於如何擴展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)
}
}
上面的代碼是一個觀察股票變動的一個例子,對LiveData進行了拓展,實現了LiveData的兩個空方法onActive和onInactive。當Active狀態的觀察者的數量從0變爲1時會調用onActive方法,通俗來講,就是當LiveData對象具有Active狀態的觀察者時調用onActive方法,應該在onActive方法中開始觀察股票價格的更新。當LiveData對象沒有任何Active狀態的觀察者時調用onInactive方法,在這個方法中,斷開與StockManager服務的連接。
LiveData
對象具有生命週期感知能力,這一事實意味着您可以在多個 Activity、Fragment 和 Service 之間共享它們。爲使示例保持簡單,所以可以將 LiveData
類實現爲單一實例,如下所示:
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
實例。僅當一個或多個系統服務可見且處於活躍狀態時,LiveData 纔會連接到該服務。
四、總結
這篇文章主要介紹了什麼是LiveData,以及LiveData的使用方法,這裏沒有介紹LiveData
和ViewModel
的結合使用,以及LiveData的原理,這些會在後面的文章進行介紹。
最後文章中涉及到的源碼及Jetpack的全組件均上傳至OnexZgj/Jetpack_Component