Android MVVM 架構到現在相信大家都很熟悉了
其中LiveData 應該也是用到爛掉了吧。
大家一定會遇到這種案子:
有個案子需要一個search清單頁面,理所當然就會想到用LiveData 來監聽資料,但是如果要加入動態Filter條件時。是否大家都會感到困惑呢
今天要來介紹 LiveData 的好兄弟 Transfotmation switchMap
Case: 一個search清單頁面且要加入動態Filter條件。
我先介紹暴力解決上面敘述的case
方法一: 每次search時產生一個 MutableLiveData 並且 監聽他
class SearchInfoViewModel() : ViewModel() { ... fun search(key: String): MutableLiveData<List<String>> { return repository.search(key) } }
這看起來簡單暴力吧!但在observer search的地方會沒包裝好的話會到處都是。
每個search事件後都會監聽它,導致產生一堆observer需要聽,用不好的話還會產生多次的呼叫
耗效能又耗資源。
直接回傳LiveData方法不行,那使用 MediatorLiveData 就好了吧,我只要改變source就行了吧
fun search(key: String): MutableLiveData<List<String>> { return MediatorLiveData<List<String>>().apply { this.addSource(queryLiveData, Observer { // get data list val list = repository.search(key) postValue(list) }) } }
簡單敘述一下, 利用 MediatorLiveData 來達到監聽的功用,並且回傳 MutableLiveData 回去
要寫好一點的話,還需要 “移除已有的source”來控管。
這麼常用的東西,應該有人包裝好了吧
我還是想在一個地方監聽資料, 更改 LiveData 的搜尋條件,原本監聽的observer便觸發更新資料,這樣不是簡單明瞭嗎?
找了一陣子,終於讓我找到 Transfotmation switchMap
Transfotmation switchMap
這物件會把變動的key 也就是query條件作為Livedata,它其值改變時變觸發query的動作
所以我們可以只監聽 Transformations.switchMap 回傳的 LiveData,而改變 query 條件時,便不用再額外監聽其他東西,整個code看起來會簡單明瞭許多
且回傳次數,都只有一次而已。
Transfotmation switchMap source code
@MainThread public static <X, Y> LiveData<Y> switchMap( @NonNull LiveData<X> source, @NonNull final Function<X, LiveData<Y>> switchMapFunction) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); result.addSource(source, new Observer<X>() { LiveData<Y> mSource; @Override public void onChanged(@Nullable X x) { LiveData<Y> newLiveData = switchMapFunction.apply(x); if (mSource == newLiveData) { return; } if (mSource != null) { result.removeSource(mSource); } mSource = newLiveData; if (mSource != null) { result.addSource(mSource, new Observer<Y>() { @Override public void onChanged(@Nullable Y y) { result.setValue(y); } }); } } }); return result; }
其原理與MediatorLiveData做法差不多,但他有幫我們控管 source的部分,不會回傳多次。
而我們也只許聽一個LiveData。
簡單來說就是google 幫我們封裝好了,讓 LIveData 更好使用。
其用法如下:
val babyGalleries: LiveData> =
Transformations.switchMap(queryLiveData) {
babyGalleryRepository.getBabyGallery(it)
}
fun query(key: String) {
queryLiveData.postValue(key)
}
總結
當你要以某個Key來更新LiveData的直時,可以用 Transfotmation switchMap 來達成需求。
參考來源
https://ithelp.ithome.com.tw/articles/10194101
https://developer.android.com/reference/android/arch/lifecycle/Transformations
2024/5/11 補充
在 androidx.lifecycle:lifecycle-livedata-ktx:2.7.0 版本下。
livedata 有支援 switchMap 的 extension 擴充方式,並廢棄了Transfotmation方式
可以直接使用 livedata.switchMap 處理
留言列表