close

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&gt; = 
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

arrow
arrow

    Owen Chen 發表在 痞客邦 留言(0) 人氣()