前言
從事Android開發兩年有余了,從15年開始學習Android,到17年開始實際接觸企業級Android APP的開發,這一路也從MVC走到了MVP。19年辭職后,休息期間研究了一下最新的Android Jetpack,萌生了一個大膽的想法——計劃使用當前各類成熟的框架和技術如組件化、插件化、MVVM等等,結合AAC開發出一個自己之前從未走過的Android開發之路。
本篇文章是LiveData的初探,會用盡可能簡潔的方式來了解LiveData,讓我們對LiveData有一個初步印象,不會長篇大論或者源碼轟炸,導致干貨太多引起閱讀困難。
目錄
- LiveData生命周期與簡介
- LiveData的使用
- LiveDataAPI介紹
- LiveData的擴展
- LiveData數據轉換
正文
LiveData簡介
LiveData的官方文檔是這樣介紹它的,
LiveData是一種具有生命周期感知能力的可觀察數據持有類。
從它介紹中我們可以知道,LiveData是一個持有數據的類,同時可以感知Activity或Fragment的生命周期,并且支持觀察者模式。
LiveData的使用
根據官方的介紹,可以按照以下的步驟來使用LiveData
1.創建一個LiveData的實例來保存特定類型的數據。 一般會把LiveData的實例定義在ViewModel類中。
val name: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
MutableLiveData是LiveData的一個子類,LiveData是一個抽象類,實例化LiveData需要使用MutableLiveData。
2.創建一個定義了onChanged()方法的Observer對象,當LiveData對象保存的數據發生變化時,onChanged()方法可以進行相應的處理。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//創建viewmodel
mViewModel = ViewModelProviders.of(this).get(LiveDataViewModel::class.java)
//聲明觀察TextView對象,
mViewModel.name.observe(this, Observer {
//實現onChanged()方法,這里使用了lambda表達式,省略了onChanaged()
textview.text = it
})
}
通常在UI控制器(如Activity或Fragment)中創建Observer對象。
3.調用LiveData的observe()方法需要傳入兩個參數,第一個參數LifecycleOwner對象,LifecycleOwner是一個接口,只要UI控制器實現了該接口,可以直接傳this,Android中的Fragment和AppCompatActivity的父類都已經實現LifecycleOwner接口。第二個參數是Observer觀察者,屬于方法回調。
更新LiveData數據
MutableLiveData提供了兩個更新數據的方法
- postValue(value: T)
- setValue(value: T)
兩個方法都可以用來更新LiveData中數據,區別在與postValue可以在子線程中更新LiveData的數據,而setValue只能在UI線程中更新LiveData的數據。
注意: UI控制器(activity和fragment)只應該負責顯示數據,不應該保存任何數據,所以不要在UI控制器中創建LiveData的實例。
LiveDataAPI介紹
getValue():T
返回LiveData當前的存儲的值
hasActiveObservers():Boolean
如果當前的LiveData存在活躍的Observer對象,則返回true
hasObservers():Boolean
如果當前的LiveData存在Observer對象,則返回true
observe(@NonNull owner: LifecycleOwner, @NonNull observer: Observer<in T>)
將給定的觀察者添加到給定所有者的生命周期內的觀察者列表中。
observeForever(@NonNull observer: Observer<in T>)
注冊一個沒有關聯LifecycleOwner對象的Observer。 在這種情況下,Observer被認為始終處于活動狀態,因此當有數據變化時總是會被通知。 可以調用removeObserver(Observer)方法移除這些Observer。
removeObserver(@NonNull observer: Observer<in T>)
從觀察者列表中刪除給定的觀察者。
removeObservers(@NonNull owner: LifecycleOwner)
刪除與給定關聯的所有觀察者LifecycleOwner。
LiveData的擴展
LiveData的擴展千變萬化,這里只介紹LiveData的源碼中預留的兩個空實現方法的擴展
- onActive()
當LiveData對象有一個活躍的Observer時,onActive()方法被調用。
- onInactive()
當LiveData對象沒有任何活躍的Observer時,onInactive()方法被調用。
通過onActive和onInactive方法我們可以很輕松的知道當前LiveData對象是否有正在活躍的觀察者對象,并根據業務邏輯作出合適的調整。
LiveData對象具有感知生命周期的能力意味著可以在多個Activity,Fragment和service之間共享它們。 為了保持簡潔,可以使用單例模式實現LiveData
class ExpandLiveData :LiveData<String>() {
companion object {
private lateinit var sInstance: ExpandLiveData
@MainThread
fun get(): ExpandLiveData {
sInstance = if (::sInstance.isInitialized) sInstance else ExpandLiveData()
return sInstance
}
}
//當活動的觀察者數量從0變為1時調用。
override fun onActive() {
super.onActive()
}
//當活動的觀察者數量從1變為0時調用。
override fun onInactive() {
super.onInactive()
}
}
在activity中就可以用如下的方式調用
ExpandLiveData.get().observe(this, Observer {
//doSomething
})
LiveData的數據轉換
通過上述的介紹,我們對LiveData有了一個初步的印象,LiveData是一個可以感知生命周期的的數據持有類,同時支持觀察者模式。說到觀察者模式,我們一定會聯想到Rxjava,Rxjava中提供了多種多樣的操作符,極大的便利了Android開發。LiveData的開發者們同樣也給LiveData帶來了與Rxjava類似的多種操作符。
與Rxjava不同的是,在LiveData中需要借助Transformations類來完成LiveData的數據轉換
- map(liveData,function)
map操作符,與rxjava的map操作符語義非常相似,可修改LiveData的輸出值。map方法有兩個參數,第一個參數是需要轉換的LiveData源,第二個參數是自定義的轉換方法。示例如下:
val newLiveData = Transformations.map(ExpandLiveData.get()) { string ->
//把轉換前的livedata的value加了一個new
"new$string"
}
newLiveData.observe(this, Observer { string ->
Log.e("newLiveData", string)
})
ExpandLiveData.get().observe(this, Observer { string ->
Log.e("ExpandLiveData", string);
})
輸出結果:
E/newLiveData: newExpand
E/ExpandLiveData: Expand
- switchMap
switchMap與map相似,區別在于:map給出的是具體的值,而switchMap給出的是具體的LiveData。
舉個例子:有這樣一個方法getUser(Id),通過傳入用戶的Id,來查找用戶的具體信息,并返回一個LiveData<User>對象。當界面傳入的用戶Id發生變化時,需要根據Id重新查找用戶的LiveData,這時就需要解除上一個LiveData關聯界面UI信息,綁定新的UI消息。如果我們使用switchMap,就可以避免重復的解綁和綁定操作。示例如下:
//模擬查找用戶的操作,這里重新生成了一個UserLiveData
fun getUser(id: String): MutableLiveData<String> {
//返回查到的UserLiveData,value是固定link加上用戶的Id,例如:userId=1000,返回值就是link-1000
val userLiveData=MutableLiveData<String>()
userLiveData.value="link-${id}"
return userLiveData
}
//用一個按鈕來模擬修改UserId
button.setOnClickListener {
//通過隨機數動態修改userId
userIdLiveData.value = Random.nextInt(0, 10000).toString()
}
//通過switchMap動態返回不同Id的UserLiveData
val userIdLiveData = MutableLiveData<String>()
Transformations.switchMap(userIdLiveData) { userId ->
Log.e("switchMap", userId)
getUser(userId)
}.observe(this, Observer {
//輸出當前getUser()中返回的UserLiveData的值
Log.e("userLiveData", it)
})
輸出結果:
E/switchMap: 9320
E/userLiveData: link-9320
E/switchMap: 7116
E/userLiveData: link-7116
通過上面例子我們可以看到,不管需要查找多少個用戶的LiveData,界面都只需要觀察生成的LiveData一次即可。
- MediatorLiveData
如果map和switchMap都不能滿足你對數據格式轉換的需求,那么還可以使用MediatorLiveData進行自定義的數據轉換。
MediatorLiveData是LiveData的一個子類,它可以添加或者移除多個源LiveData對象,將多個源LiveData對象組合一個單一的LiveData對象。任何LiveData源對象發生改變后,MediatorLiveData的Observer都會被觸發。
上面的map和switchMap的底層實現實際上也是使用了MediatorLiveData,我們可以簡單看一下map的源碼,來對MediatorLiveData的使用又一個大致的了解。
@MainThread
public static <X, Y> LiveData<Y> map(
@NonNull LiveData<X> source,
@NonNull final Function<X, Y> mapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(mapFunction.apply(x));
}
});
return result;
}
MediatorLiveData的使用暫時先不介紹,我們只需要對它有個大致的了解,具體的細節,會在后續的文章中介紹。
總結
本篇文章的簡要介紹了LiveData是什么,以及如何使用LiveData。其實只要記住LiveData本質上就是一個可以感知生命周期的數據持有類,支持觀察者模式,就可以了,其他的細節幾乎都是對其特性的擴展。當我們記牢LiveData的特性后,或許就不會在開發中產生“我為毛要使用LiveData”的疑問了。
在AAC架構中LiveData和ViewModel占據了很重要的位置,下一篇我們再來介紹ViewModel。