關(guān)于Transformations.map和Transformations.switchMap的一些理解

用了 Android Architecture Component ** 也有一段時(shí)間了,期間也遇到過不少問題稚晚,也慢慢的解決了炊昆。mapswitchmap**是 LiveData Transformations提供的兩個(gè)方法缝其,那具體能干些啥呢盗胀?這是個(gè)好問題。如果知道RxJava,那么可以簡單的對標(biāo) map和flatmap沸手,咱先這么理解著外遇,對不對先不管,起碼契吉,腦子中有個(gè)概念跳仿。

Transformations.map

先上源碼

    /**
     * Applies the given function on the main thread to each value emitted by {@code source}
     * LiveData and returns LiveData, which emits resulting values.
     * <p>
     * The given function {@code func} will be executed on the main thread.
     * <p>
     * Suppose that you have a LiveData, named {@code userLiveData}, that contains user data and you
     * need to display the user name, created by concatenating the first and the last
     * name of the user. You can define a function that handles the name creation, that will be
     * applied to every value emitted by {@code useLiveData}.
     *
     * <pre>
     * LiveData<User> userLiveData = ...;
     * LiveData<String> userName = Transformations.map(userLiveData, user -> {
     *      return user.firstName + " " + user.lastName
     * });
     * </pre>
     *
     * @param source a {@code LiveData} to listen to
     * @param func   a function to apply
     * @param <X>    a type of {@code source} LiveData
     * @param <Y>    a type of resulting LiveData.
     * @return a LiveData which emits resulting values
     */
   @MainThread
    public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source,
            @NonNull final Function<X, Y> func) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(source, new Observer<X>() {
            @Override
            public void onChanged(@Nullable X x) {
                result.setValue(func.apply(x));
            }
        });
        return result;
    }

就是 傳進(jìn)去一個(gè)Livedata形式的參數(shù)和一個(gè)方法,然后將這個(gè)LiveData捐晶。通過方法中的邏輯再輸出為LiveData,最簡單的用法就是像kotlin集合中的map用法菲语。將集合中每個(gè)元素,做你方法中的操作惑灵,比如加減之類的山上。源碼中的那個(gè)注釋大概就是這個(gè)各操作,
我們來擴(kuò)展一下英支,假設(shè)現(xiàn)在有這么一個(gè)場景:界面上有個(gè)輸入框佩憾,你輸入一些字母 然后添加到數(shù)據(jù)庫中。完了之后彈個(gè)吐司干花。
我們來簡寫一下viewmodel中的代碼:

val  strLivedata=MutableLiveData<String>()
fun yourFun(str:String)="新${str}被添加到數(shù)據(jù)庫中"
fun addStrClick(str:String)= { strLivedata.value=str}
val addStr:LiveData=Transformations.map(strLivedata, ::yourFun)

然后Activity中的代碼:

viewModel.addSt.observe(this, Observer{
吐司(it)
})

button.setOnClickListener {
viewModel.addStr(edittext.text.toString())
}

恩妄帘,基本上就是這樣

Transformations.switchMap

switchmap 說實(shí)話,一開始的時(shí)候池凄,我立即起來和用起來抡驼,比較費(fèi)勁,尤其是配合了lamada表達(dá)式肿仑,更是難受致盟。
先上源碼:


 /**
     * Creates a LiveData, let's name it {@code swLiveData}, which follows next flow:
     * it reacts on changes of {@code trigger} LiveData, applies the given function to new value of
     * {@code trigger} LiveData and sets resulting LiveData as a "backing" LiveData
     * to {@code swLiveData}.
     * "Backing" LiveData means, that all events emitted by it will retransmitted
     * by {@code swLiveData}.
     * <p>
     * If the given function returns null, then {@code swLiveData} is not "backed" by any other
     * LiveData.
     *
     * <p>
     * The given function {@code func} will be executed on the main thread.
     *
     * <p>
     * Consider the case where you have a LiveData containing a user id. Every time there's a new
     * user id emitted, you want to trigger a request to get the user object corresponding to that
     * id, from a repository that also returns a LiveData.
     * <p>
     * The {@code userIdLiveData} is the trigger and the LiveData returned by the {@code
     * repository.getUserById} is the "backing" LiveData.
     * <p>
     * In a scenario where the repository contains User(1, "Jane") and User(2, "John"), when the
     * userIdLiveData value is set to "1", the {@code switchMap} will call {@code getUser(1)},
     * that will return a LiveData containing the value User(1, "Jane"). So now, the userLiveData
     * will emit User(1, "Jane"). When the user in the repository gets updated to User(1, "Sarah"),
     * the {@code userLiveData} gets automatically notified and will emit User(1, "Sarah").
     * <p>
     * When the {@code setUserId} method is called with userId = "2", the value of the {@code
     * userIdLiveData} changes and automatically triggers a request for getting the user with id
     * "2" from the repository. So, the {@code userLiveData} emits User(2, "John"). The LiveData
     * returned by {@code repository.getUserById(1)} is removed as a source.
     *
     * <pre>
     * MutableLiveData<String> userIdLiveData = ...;
     * LiveData<User> userLiveData = Transformations.switchMap(userIdLiveData, id ->
     *     repository.getUserById(id));
     *
     * void setUserId(String userId) {
     *      this.userIdLiveData.setValue(userId);
     * }
     * </pre>
     *
     * @param trigger a {@code LiveData} to listen to
     * @param func    a function which creates "backing" LiveData
     * @param <X>     a type of {@code source} LiveData
     * @param <Y>     a type of resulting LiveData
     */
    @MainThread
    public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger,
            @NonNull final Function<X, LiveData<Y>> func) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(trigger, new Observer<X>() {
            LiveData<Y> mSource;

            @Override
            public void onChanged(@Nullable X x) {
                LiveData<Y> newLiveData = func.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;
    }

怎么理解呢,先看注釋上的那個(gè)例子尤慰。
定義一個(gè)用戶id字符串的livedata勾邦,一個(gè)用戶的livedata是通過Transformations.switchMap賦值的,就是傳進(jìn)去userid的livedata割择,然后通過這個(gè)id,去獲取這個(gè)用戶信息萎河。再提供一個(gè)設(shè)置userid的方法荔泳,這樣流程就串起來了蕉饼。我們來擴(kuò)展下:輸入框中輸入一個(gè)字符串,然后搜索玛歌,然后調(diào)用接口或者其他昧港,用recycleview展示出來。
先看viewModel中的代碼:

//查詢的關(guān)鍵字livedata
val query = MutableLiveData<String>()
//你點(diǎn)擊搜索是調(diào)用的方法
   fun queryByStr(str: String) = apply { query.value = str}
//你的處理方法
fun yourFun(str:String):LiveData<List<String>>{
return 你網(wǎng)絡(luò)或者數(shù)據(jù)庫.query(str)
}

//查詢結(jié)果livedata
val queryResult=LiveData<List<String>>=Transformations.switchMap(
            query,
            ::yourFun
    )

再看activity中的代碼:

recycleview初始化支子,設(shè)置adapter就不寫了

搜索.setOnClickListener{
viewModel.queryByStr(搜索框.text.toString())}
viewModel.queryResult.observe(this,Observer {
//搜索結(jié)果變化了
直接給adapter的數(shù)據(jù)源list改變创肥,然后notify一下就完事了
})

大概基本上差不多就這樣了,怎么說呢值朋,光看代碼的話叹侄,其實(shí)也不難理解,主要是本人對lamada表達(dá)是有點(diǎn)怵的慌昨登,尤其是配合kotlin趾代,本來一長串,結(jié)果給省略掉了丰辣,看起來賊費(fèi)事撒强,當(dāng)然了。這個(gè)主要跟我的基礎(chǔ)語法有關(guān)系笙什,如果你深諳lamada表達(dá)式飘哨,那就沒毛病了∷銎荆總結(jié)一下芽隆。這兩個(gè)操作符。map是你將你的函數(shù)用于你傳參的livedata的數(shù)據(jù)通過函數(shù)體中的邏輯改變淘正,然后將結(jié)果傳到下游摆马。而switchmap,轉(zhuǎn)換跟map差不多鸿吆,只不過傳到下游的是livedata類型囤采。rxjava中,map的作用是操作基本函數(shù)類型惩淳,而flatmap操作的是observable類型蕉毯。當(dāng)然了,還有一些能深入去理解的東西思犁,我還沒理解到代虾。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市激蹲,隨后出現(xiàn)的幾起案子棉磨,更是在濱河造成了極大的恐慌,老刑警劉巖学辱,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乘瓤,死亡現(xiàn)場離奇詭異环形,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)衙傀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門抬吟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人统抬,你說我怎么就攤上這事火本。” “怎么了聪建?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵钙畔,是天一觀的道長。 經(jīng)常有香客問我妆偏,道長刃鳄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任钱骂,我火速辦了婚禮叔锐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘见秽。我一直安慰自己愉烙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布解取。 她就那樣靜靜地躺著步责,像睡著了一般。 火紅的嫁衣襯著肌膚如雪禀苦。 梳的紋絲不亂的頭發(fā)上蔓肯,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機(jī)與錄音振乏,去河邊找鬼蔗包。 笑死,一個(gè)胖子當(dāng)著我的面吹牛慧邮,可吹牛的內(nèi)容都是我干的调限。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼误澳,長吁一口氣:“原來是場噩夢啊……” “哼耻矮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起忆谓,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤裆装,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哨免,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勾扭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了铁瞒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桅滋,死狀恐怖慧耍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情丐谋,我是刑警寧澤芍碧,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站号俐,受9級特大地震影響泌豆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吏饿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一踪危、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧猪落,春花似錦贞远、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至官疲,卻和暖如春袱结,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背途凫。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工垢夹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人颖榜。 一個(gè)月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓棚饵,卻偏偏與公主長得像,于是被迫代替她去往敵國和親掩完。 傳聞我的和親對象是個(gè)殘疾皇子噪漾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容