轉(zhuǎn)換操作符

buffer操作符

buffer操作符周期性地收集源Observable產(chǎn)生的結(jié)果到列表中,并把這個(gè)列表提交給訂閱者,訂閱者處理后,清空buffer列表,同時(shí)接收下一次收集的結(jié)果并提交給訂閱者,周而復(fù)始。
一旦源Observable在產(chǎn)生結(jié)果的過(guò)程中出現(xiàn)異常,即使buffer已經(jīng)存在收集到的結(jié)果,訂閱者也會(huì)馬上收到這個(gè)異常,并結(jié)束整個(gè)過(guò)程。
buffer操作符

//定義郵件內(nèi)容
        final String[] mails = new String[]{"Here is an email!", "Another email!", "Yet another email!"};
        //每隔1秒就隨機(jī)發(fā)布一封郵件
        Observable<String> endlessMail = Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                try {
                    if (subscriber.isUnsubscribed()) return;
                    Random random = new Random();
                    while (true) {
                        String mail = mails[random.nextInt(mails.length)];
                        subscriber.onNext(mail);
                        Thread.sleep(1000);
                    }
                } catch (Exception ex) {
                    subscriber.onError(ex);
                }
            }
        }).subscribeOn(Schedulers.io());
        //把上面產(chǎn)生的郵件內(nèi)容緩存到列表中,并每隔3秒通知訂閱者
        endlessMail.buffer(3, TimeUnit.SECONDS).subscribe(new Action1<List<String>>() {
            @Override
            public void call(List<String> list) {

                System.out.println(String.format("You've got %d new messages!  Here they are!", list.size()));
                for (int i = 0; i < list.size(); i++)
                    System.out.println("**" + list.get(i).toString());
            }
        });

運(yùn)行結(jié)果如下:
You’ve got 3 new messages! Here they are!(after 3s)
**Here is an email!
**Another email!
**Another email!
You’ve got 3 new messages! Here they are!(after 6s)
**Here is an email!
**Another email!
**Here is an email!
……


flatMap操作符

flatMap操作符是把Observable產(chǎn)生的結(jié)果轉(zhuǎn)換成多個(gè)Observable,然后把這多個(gè)Observable“扁平化”成一個(gè)Observable,并依次提交產(chǎn)生的結(jié)果給訂閱者。
flatMap操作符通過(guò)傳入一個(gè)函數(shù)作為參數(shù)轉(zhuǎn)換源Observable,在這個(gè)函數(shù)中,你可以自定義轉(zhuǎn)換規(guī)則,最后在這個(gè)函數(shù)中返回一個(gè)新的Observable,然后flatMap操作符通過(guò)合并這些Observable結(jié)果成一個(gè)Observable,并依次提交結(jié)果給訂閱者。
flatMap操作符在合并Observable結(jié)果時(shí),有可能存在交叉的情況

private Observable<File> listFiles(File f){
        if(f.isDirectory()){
            return Observable.from(f.listFiles()).flatMap(new Func1<File, Observable<File>>() {
                @Override
                public Observable<File> call(File file) {
                    return listFiles(f);
                }
            });
        } else {
            return Observable.just(f);
        }
    }


    @Override
    public void onClick(View v) {
        Observable.just(getApplicationContext().getExternalCacheDir())
                .flatMap(new Func1<File, Observable<File>>() {
                    @Override
                    public Observable<File> call(File file) {
                        //參數(shù)file是just操作符產(chǎn)生的結(jié)果,這里判斷file是不是目錄文件,如果是目錄文件,則遞歸查找其子文件flatMap操作符神奇的地方在于,返回的結(jié)果還是一個(gè)Observable,而這個(gè)Observable其實(shí)是包含多個(gè)文件的Observable的,輸出應(yīng)該是ExternalCacheDir下的所有文件
                        return listFiles(file);
                    }
                })
                .subscribe(new Action1<File>() {
                    @Override
                    public void call(File file) {
                        System.out.println(file.getAbsolutePath());
                    }
                });

    }
concatMap操作符

cancatMap操作符與flatMap操作符類似,都是把Observable產(chǎn)生的結(jié)果轉(zhuǎn)換成多個(gè)Observable,然后把這多個(gè)Observable“扁平化”成一個(gè)Observable,并依次提交產(chǎn)生的結(jié)果給訂閱者。
與flatMap操作符不同的是,concatMap操作符在處理產(chǎn)生的Observable時(shí),采用的是“連接(concat)”的方式,而不是“合并(merge)”的方式,這就能保證產(chǎn)生結(jié)果的順序性,也就是說(shuō)提交給訂閱者的結(jié)果是按照順序提交的,不會(huì)存在交叉的情況。

switchMap操作符

switchMap操作符與flatMap操作符類似,都是把Observable產(chǎn)生的結(jié)果轉(zhuǎn)換成多個(gè)Observable,然后把這多個(gè)Observable“扁平化”成一個(gè)Observable,并依次提交產(chǎn)生的結(jié)果給訂閱者。
與flatMap操作符不同的是,switchMap操作符會(huì)保存最新的Observable產(chǎn)生的結(jié)果而舍棄舊的結(jié)果,舉個(gè)例子來(lái)說(shuō),比如源Observable產(chǎn)生A、B、C三個(gè)結(jié)果,通過(guò)switchMap的自定義映射規(guī)則,映射后應(yīng)該會(huì)產(chǎn)生A1、A2、B1、B2、C1、C2,但是在產(chǎn)生B2的同時(shí),C1已經(jīng)產(chǎn)生了,這樣最后的結(jié)果就變成A1、A2、B1、C1、C2,B2被舍棄掉了!

以下是flatMap、concatMap和switchMap的運(yùn)行實(shí)例對(duì)比:

        //flatMap操作符的運(yùn)行結(jié)果
        Observable.just(10, 20, 30).flatMap(new Func1<Integer, Observable<Integer>>() {
            @Override
            public Observable<Integer> call(Integer integer) {
                //10的延遲執(zhí)行時(shí)間為200毫秒、20和30的延遲執(zhí)行時(shí)間為180毫秒
                int delay = 200;
                if (integer > 10)
                    delay = 180;

                return Observable.from(new Integer[]{integer, integer / 2}).delay(delay, TimeUnit.MILLISECONDS);
            }
        }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer integer) {
                System.out.println("flatMap Next:" + integer);
            }
        });

        //concatMap操作符的運(yùn)行結(jié)果
        Observable.just(10, 20, 30).concatMap(new Func1<Integer, Observable<Integer>>() {
            @Override
            public Observable<Integer> call(Integer integer) {
                //10的延遲執(zhí)行時(shí)間為200毫秒、20和30的延遲執(zhí)行時(shí)間為180毫秒
                int delay = 200;
                if (integer > 10)
                    delay = 180;

                return Observable.from(new Integer[]{integer, integer / 2}).delay(delay, TimeUnit.MILLISECONDS);
            }
        }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer integer) {
                System.out.println("concatMap Next:" + integer);
            }
        });

        //switchMap操作符的運(yùn)行結(jié)果
        Observable.just(10, 20, 30).switchMap(new Func1<Integer, Observable<Integer>>() {
            @Override
            public Observable<Integer> call(Integer integer) {
                //10的延遲執(zhí)行時(shí)間為200毫秒、20和30的延遲執(zhí)行時(shí)間為180毫秒
                int delay = 200;
                if (integer > 10)
                    delay = 180;

                return Observable.from(new Integer[]{integer, integer / 2}).delay(delay, TimeUnit.MILLISECONDS);
            }
        }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer integer) {
                System.out.println("switchMap Next:" + integer);
            }
        });

運(yùn)行結(jié)果如下:
flatMap Next:20
flatMap Next:10
flatMap Next:30
flatMap Next:15
flatMap Next:10
flatMap Next:5

switchMap Next:30
switchMap Next:15

concatMap Next:10
concatMap Next:5
concatMap Next:20
concatMap Next:10
concatMap Next:30
concatMap Next:15


groupBy操作符

groupBy操作符是對(duì)源Observable產(chǎn)生的結(jié)果進(jìn)行分組,形成一個(gè)類型為GroupedObservable的結(jié)果集,GroupedObservable中存在一個(gè)方法為getKey(),可以通過(guò)該方法獲取結(jié)果集的Key值(類似于HashMap的key)。
值得注意的是,由于結(jié)果集中的GroupedObservable是把分組結(jié)果緩存起來(lái),如果對(duì)每一個(gè)GroupedObservable不進(jìn)行處理(既不訂閱執(zhí)行也不對(duì)其進(jìn)行別的操作符運(yùn)算),就有可能出現(xiàn)內(nèi)存泄露。因此,如果你對(duì)某個(gè)GroupedObservable不進(jìn)行處理,最好是對(duì)其使用操作符take(0)處理。
groupBy操作符的流程圖如下

調(diào)用例子如下:

Observable.interval(1, TimeUnit.SECONDS).take(10).groupBy(new Func1<Long, Long>() {
            @Override
            public Long call(Long value) {
                //按照key為0,1,2分為3組
                return value % 3;
            }
        }).subscribe(new Action1<GroupedObservable<Long, Long>>() {
            @Override
            public void call(GroupedObservable<Long, Long> result) {
                result.subscribe(new Action1<Long>() {
                    @Override
                    public void call(Long value) {
                        System.out.println("key:" + result.getKey() +", value:" + value);
                    }
                });
            }
        });

運(yùn)行結(jié)果如下:
key:0, value:0
key:1, value:1
key:2, value:2
key:0, value:3
key:1, value:4
key:2, value:5
key:0, value:6
key:1, value:7
key:2, value:8
key:0, value:9


map操作符

map操作符是把源Observable產(chǎn)生的結(jié)果,通過(guò)映射規(guī)則轉(zhuǎn)換成另一個(gè)結(jié)果集,并提交給訂閱者進(jìn)行處理。

Observable.just(1,2,3,4,5,6).map(new Func1<Integer, Integer>() {
            @Override
            public Integer call(Integer integer) {
                //對(duì)源Observable產(chǎn)生的結(jié)果,都統(tǒng)一乘以3處理
                return integer*3;
            }
        }).subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer integer) {
                System.out.println("next:" + integer);
            }
        });

運(yùn)行結(jié)果如下:
next:3
next:6
next:9
next:12
next:15
next:18


cast操作符

cast操作符類似于map操作符,不同的地方在于map操作符可以通過(guò)自定義規(guī)則,把一個(gè)值A(chǔ)1變成另一個(gè)值A(chǔ)2,A1和A2的類型可以一樣也可以不一樣;而cast操作符主要是做類型轉(zhuǎn)換的,傳入?yún)?shù)為類型class,如果源Observable產(chǎn)生的結(jié)果不能轉(zhuǎn)成指定的class,則會(huì)拋出ClassCastException運(yùn)行時(shí)異常。

        Observable.just(1,2,3,4,5,6).cast(Integer.class).subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer value) {
                System.out.println("next:"+value);
            }
        });

運(yùn)行結(jié)果如下:
next:1
next:2
next:3
next:4
next:5
next:6


scan操作符

scan操作符通過(guò)遍歷源Observable產(chǎn)生的結(jié)果,依次對(duì)每一個(gè)結(jié)果項(xiàng)按照指定規(guī)則進(jìn)行運(yùn)算,計(jì)算后的結(jié)果作為下一個(gè)迭代項(xiàng)參數(shù),每一次迭代項(xiàng)都會(huì)把計(jì)算結(jié)果輸出給訂閱者。

Observable.just(1, 2, 3, 4, 5)
    .scan(new Func2<Integer, Integer, Integer>() {
        @Override
        public Integer call(Integer sum, Integer item) {
            //參數(shù)sum就是上一次的計(jì)算結(jié)果
            return sum + item;
        }
    }).subscribe(new Subscriber<Integer>() {
        @Override
        public void onNext(Integer item) {
            System.out.println("Next: " + item);
        }

        @Override
        public void onError(Throwable error) {
            System.err.println("Error: " + error.getMessage());
        }

        @Override
        public void onCompleted() {
            System.out.println("Sequence complete.");
        }
    });

運(yùn)行結(jié)果如下:
Next: 1
Next: 3
Next: 6
Next: 10
Next: 15
Sequence complete.


window操作符

window操作符非常類似于buffer操作符,區(qū)別在于buffer操作符產(chǎn)生的結(jié)果是一個(gè)List緩存,而window操作符產(chǎn)生的結(jié)果是一個(gè)Observable,訂閱者可以對(duì)這個(gè)結(jié)果Observable重新進(jìn)行訂閱處理。

Observable.interval(1, TimeUnit.SECONDS).take(12)
                .window(3, TimeUnit.SECONDS)
                .subscribe(new Action1<Observable<Long>>() {
                    @Override
                    public void call(Observable<Long> observable) {
                        System.out.println("subdivide begin......");
                        observable.subscribe(new Action1<Long>() {
                            @Override
                            public void call(Long aLong) {
                                System.out.println("Next:" + aLong);
                            }
                        });
                    }
                });

運(yùn)行結(jié)果如下:
subdivide begin……
Next:0
Next:1
subdivide begin……
Next:2
Next:3
Next:4
subdivide begin……
Next:5
Next:6
Next:7
subdivide begin……
Next:8
Next:9
Next:10
subdivide begin……
Next:11


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,716評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,706評(píng)論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,036評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,203評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,725評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,451評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,677評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,857評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,407評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,643評(píng)論 2 380

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