RxJava入門與提高-操作符篇(3)

前言

按照官方的分類,操作符大致分為以下幾種:

  • Creating Observables(Observable的創建操作符),比如:Observable.create()、Observable.just()、Observable.from()等等;
  • Transforming Observables(Observable的轉換操作符),比如:observable.map()、observable.flatMap()、observable.buffer()等等;
  • Filtering Observables(Observable的過濾操作符),比如:observable.filter()、observable.sample()、observable.take()等等;
  • Combining Observables(Observable的組合操作符),比如:observable.join()、observable.merge()、observable.combineLatest()等等;
  • Error Handling Operators(Observable的錯誤處理操作符),比如:observable.onErrorResumeNext()、observable.retry()等等;
  • Observable Utility Operators(Observable的功能性操作符),比如:observable.subscribeOn()、observable.observeOn()、observable.delay()等等;
  • Conditional and Boolean Operators(Observable的條件操作符),比如:observable.amb()、observable.contains()、observable.skipUntil()等等;
  • Mathematical and Aggregate Operators(Observable數學運算及聚合操作符),比如:observable.count()、observable.reduce()、observable.concat()等等;
  • 其他如observable.toList()、observable.connect()、observable.publish()等等;

1、創建型操作符

  • create操作符

create操作符是所有創建型操作符的“根”,也就是說其他創建型操作符最后都是通過create操作符來創建Observable的

  • from操作符

from操作符是把其他類型的對象和數據類型轉化成Observable

  • just操作符

just操作符也是把其他類型的對象和數據類型轉化成Observable,它和from操作符很像,只是方法的參數有所差別

  • defer操作符

defer操作符是直到有訂閱者訂閱時,才通過Observable的工廠方法創建Observable并執行

  • timer操作符

timer操作符是創建一串連續的數字,產生這些數字的時間間隔是一定的

  • interval操作符

interval操作符是每隔一段時間就產生一個數字,這些數字從0開始,一次遞增1直至無窮大;interval操作符的實現效果跟上面的timer操作符的第二種情形一樣

  • range操作符

range操作符是創建一組在從n開始,個數為m的連續數字,比如range(3,10),就是創建3、4、5…12的一組數字

  • repeat/repeatWhen操作符

repeat操作符是對某一個Observable,重復產生多次結果

repeatWhen操作符是對某一個Observable,有條件地重新訂閱從而產生多次結果


2、Observable的轉換操作符

  • buffer

buffer操作符周期性地收集源Observable產生的結果到列表中,并把這個列表提交給訂閱者,訂閱者處理后,清空buffer列表,同時接收下一次收集的結果并提交給訂閱者,周而復始

  • flatmap

把Observable產生的結果轉換成多個Observable,然后把這多個Observable“扁平化”成一個Observable,并依次提交產生的結果給訂閱者

  • concatMap操作符

flatMap操作符不同的是,concatMap操作符在處理產生的Observable時,采用的是“連接(concat)”的方式,而不是“合并(merge)”的方式,這就能保證產生結果的順序性,也就是說提交給訂閱者的結果是按照順序提交的,不會存在交叉的情況

  • switchMap

與flatMap操作符不同的是,switchMap操作符會保存最新的Observable產生的結果而舍棄舊的結果

  • groupBy操作符

groupBy操作符是對源Observable產生的結果進行分組,形成一個類型為GroupedObservable的結果集,GroupedObservable中存在一個方法為getKey(),可以通過該方法獲取結果集的Key值

  • cast操作符

而cast操作符主要是做類型轉換的

  • scan操作符

scan操作符通過遍歷源Observable產生的結果,依次對每一個結果項按照指定規則進行運算,計算后的結果作為下一個迭代項參數,每一次迭代項都會把計算結果輸出給訂閱者

  • window操作符

window操作符非常類似于buffer操作符,區別在于buffer操作符產生的結果是一個List緩存,而window操作符產生的結果是一個Observable,訂閱者可以對這個結果Observable重新進行訂閱處理


3、Observable的過濾操作符

  • debounce操作符

debounce操作符對源Observable每產生一個結果后,如果在規定的間隔時間內沒有別的結果產生,則把這個結果提交給訂閱者處理,否則忽略該結果。

  • distinct操作符

distinct操作符對源Observable產生的結果進行過濾,把重復的結果過濾掉,只輸出不重復的結果給訂閱者,非常類似于SQL里的distinct關鍵字。

  • elementAt操作符

elementAt操作符在源Observable產生的結果中,僅僅把指定索引的結果提交給訂閱者,索引是從0開始的

  • filter操作符

filter操作符是對源Observable產生的結果按照指定條件進行過濾,只有滿足條件的結果才會提交給訂閱者

  • ofType操作符

ofType操作符類似于filter操作符,區別在于ofType操作符是按照類型對結果進行過濾

  • first操作符

first操作符是把源Observable產生的結果的第一個提交給訂閱者,first操作符可以使用elementAt(0)和take(1)替代

  • single操作符

single操作符是對源Observable的結果進行判斷,如果產生的結果滿足指定條件的數量不為1,則拋出異常,否則把滿足條件的結果提交給訂閱者

  • last操作符

last操作符把源Observable產生的結果的最后一個提交給訂閱者,last操作符可以使用takeLast(1)替代

  • ignoreElements操作符

ignoreElements操作符忽略所有源Observable產生的結果,只把Observable的onCompleted和onError事件通知給訂閱者。ignoreElements操作符適用于不太關心Observable產生的結果,只是在Observable結束時(onCompleted)或者出現錯誤時能夠收到通知

  • skip操作符

skip操作符針對源Observable產生的結果,跳過前面n個不進行處理,而把后面的結果提交給訂閱者處理

  • skipLast操作符

skipLast操作符針對源Observable產生的結果,忽略Observable最后產生的n個結果,而把前面產生的結果提交給訂閱者處理,

  • take操作符

take操作符是把源Observable產生的結果,提取前面的n個提交給訂閱者,而忽略后面的結果

  • takeFirst操作符

takeFirst操作符類似于take操作符,同時也類似于first操作符,都是獲取源Observable產生的結果列表中符合指定條件的前一個或多個,與first操作符不同的是,first操作符如果獲取不到數據,則會拋出NoSuchElementException異常,而takeFirst則會返回一個空的Observable,該Observable只有onCompleted通知而沒有onNext通知。

  • takeLast操作符

takeLast操作符是把源Observable產生的結果的后n項提交給訂閱者


4、Observable的組合操作符

  • combineLatest操作符

combineLatest操作符把兩個Observable產生的結果進行合并,合并的結果組成一個新的Observable。這兩個Observable中任意一個Observable產生的結果,都和另一個Observable最后產生的結果,按照一定的規則進行合并

  • join操作符

join操作符把類似于combineLatest操作符,也是兩個Observable產生的結果進行合并,合并的結果組成一個新的Observable,但是join操作符可以控制每個Observable產生結果的生命周期

  • groupJoin操作符

groupJoin操作符非常類似于join操作符,區別在于join操作符中第四個參數的傳入函數不一致

  • merge操作符

merge操作符是按照兩個Observable提交結果的時間順序,對Observable進行合并

  • mergeDelayError操作符

從merge操作符的流程圖可以看出,一旦合并的某一個Observable中出現錯誤,就會馬上停止合并,并對訂閱者回調執行onError方法,而mergeDelayError操作符會把錯誤放到所有結果都合并完成之后才執行

  • startWith操作符

startWith操作符是在源Observable提交結果之前,插入指定的某些數據

  • switchOnNext操作符

switchOnNext操作符是把一組Observable轉換成一個Observable,轉換規則為:對于這組Observable中的每一個Observable所產生的結果,如果在同一個時間內存在兩個或多個Observable提交的結果,只取最后一個Observable提交的結果給訂閱者

  • zip操作符

zip操作符是把兩個observable提交的結果,嚴格按照順序進行合并,其流程圖如下:


5、 Observable的錯誤處理操作符

  • onErrorReturn操作符

onErrorReturn操作符是在Observable發生錯誤或異常的時候(即將回調oError方法時),攔截錯誤并執行指定的邏輯,返回一個跟源Observable相同類型的結果,最后回調訂閱者的onComplete方法

  • onErrorResumeNext操作符

onErrorResumeNext操作符跟onErrorReturn類似,只不過onErrorReturn只能在錯誤或異常發生時只返回一個和源Observable相同類型的結果,而onErrorResumeNext操作符是在錯誤或異常發生時返回一個Observable,也就是說可以返回多個和源Observable相同類型的結果

  • onExceptionResumeNext操作符

onExceptionResumeNext操作符和onErrorResumeNext操作符類似,不同的地方在于onErrorResumeNext操作符是當Observable發生錯誤或異常時觸發,而onExceptionResumeNext是當Observable發生異常時才觸發

  • retry操作符

retry操作符是當Observable發生錯誤或者異常時,重新嘗試執行Observable的邏輯,如果經過n次重新嘗試執行后仍然出現錯誤或者異常,則最后回調執行onError方法;當然如果源Observable沒有錯誤或者異常出現,則按照正常流程執行




常用操作符(舉例學習)

(1)Observable.from()。

使用from( )創建Observable,遍歷集合,發送每個item:

List list = new ArrayList<>();
list.add("from1");
list.add("from2");
list.add("from3");
Observable fromObservable = Observable.from(list);  //遍歷list 每次發送一個

關于創建的操作符,我在前邊的文章里已經總結過,這里不再列舉。有興趣 的同學可以參考本系列第一篇文章 RxJava入門與提高(1)

(2)Observable.map()

用來把一個事件轉換為另一個事件。
map()操作符就是用于變換Observable對象的,map操作符返回一個Observable對象,這樣就可以實現鏈式調用,在一個Observable對象上多次使用map操作符,最終將最簡潔的數據傳遞給Subscriber對象。

特性:

它不必返回Observable對象返回的類型,你可以使用map操作符返回一個發出新的數據類型的observable對象。
可以對一個Observable多次使用map
用一個例子來練習:

//剛創建的Observable是String類型的
Observable.just("Hellp Map Operator")
.map(new Func1<String, Integer>() {
    @Override
    public Integer call(String s) {
        return 2015;//通過第一個map轉成Integer
    }
}).map(new Func1<Integer, String>() {
    @Override
    public String call(Integer integer) {
        return String.valueOf(integer);//再通過第二個map轉成String
    }
}).subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
        System.out.println(s);
    }
});

Run起來輸出日志: 2015

(3)Observable.flatMap()

Observable.flatMap()接收一個Observable的輸出作為參數輸入,同時輸出另外一個Observable。這一點很類似于map()。稍后總結flatMap()與map()。

舉例說明

 List<String> list = Arrays.asList("Java", "Android", "Ruby", "Ios", "Swift");

 //注意這里的Func1的參數List<String>是 .just(list)返回的Observable的輸出,并且返會一個Observable<String>
Observable.just(list)
.flatMap(new Func1<List<String>, Observable<String>>() {
    @Override
    public Observable<String> call(List<String> strings) {
        //結合from處理
        return Observable.from(strings);
    }
}).subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
        System.out.println("_flatMap:"+s);
    }
});



日志:

_flatMap:Java
_flatMap:Android
_flatMap:Ruby
_flatMap:Ios
_flatMap:Swift

假設這時候我們需要處理一下所獲取的結果,我們加個前綴,在保證不修改subscriber的前提下我們可以這么做:
增加個函數,用來增加個前綴:

static Observable<String>addPre(String lan){
        return Observable.just("addPre_"+lan);
}
Observable.just(list)
.flatMap(new Func1<List<String>, Observable<String>>() {
    @Override
    public Observable<String> call(List<String> strings) {
        return Observable.from(strings);
    }
}).flatMap(new Func1<String, Observable<String>>() {
    @Override
    public Observable<String> call(String s) {
        //我們在這里調用`addPre`方法,就行處理
        return addPre(s);
    }
}).subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
        System.out.println(s);
    }
});

輸出日志

addPre_Java
addPre_Android
addPre_Ruby
addPre_Ios
addPre_Swift
  • 小結 :flatMap()與map()
    (1)flatMap()與map()變換操作完后,都是返回的Observable對象,即數據源,這樣可以繼續發射數據,或者調用subscribe去叫接收員接收數據。
    (2)map()中的Func類重寫的的call()方法的入參是 轉換前的Observable對象 發射的數據內容(可以理解為Observable對象里邊包含的數據內容),返回的數據是轉換后的Observable對象要發射的數據。
    flatMap()中的Func類重寫的的call()方法的入參也是 轉換前的Observable對象 發射的數據內容,返回的數據是Observable對象。
    代碼片段
.map(new Func1<Integer, String>() {
    @Override
    public String call(Integer integer) {
        return String.valueOf(integer);//再通過第二個map轉成String,返回String
    }
})
*******************************************************
.flatMap(new Func1<String, Observable<String>>() {
    @Override
    public Observable<String> call(String s) {
        //我們在這里調用`addPre`方法,返回的是Observable<String>
        return addPre(s);
    }
}

(3)flatMap()處理集合、數組等,map()處理單一對象數據。

(4)Buffer

Buffer操作符定期收集Observable的數據放進一個數據包裹,然后發射這些數據包裹,而不是一次發射一個值。

Buffer操作符將一個Observable變換為另一個,原來的Observable正常發射數據,變換產生的Observable發射這些數據的緩存集合。

       RxView.clickEvents(mButton)
                .buffer(2, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<List<ViewClickEvent>>() {
                    @Override
                    public void onCompleted() {}
                    @Override
                    public void onError(Throwable e) {}
                    @Override
                    public void onNext(List<ViewClickEvent> viewClickEvents) {
                        if (viewClickEvents.size() > 0) {
                            Toast.makeText(MainActivity.this, "2秒內點擊了" + viewClickEvents.size() + "次", Toast.LENGTH_SHORT).show();
                        } else {

                        }
                    }
                });

如果原來的Observable發射了一個onError通知,Buffer會立即傳遞這個通知,而不是首先發射緩存的數據,即使在這之前緩存中包含了原始Observable發射的數據。

  • 再舉個栗子
    將原發射出來的數據已count為單元打包之后在分別發射出來
Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    .buffer(3)
    .subscribe(new Action1<Object>() {
        @Override
        public void call(Object o) {
            System.out.println("onNext--> " + o);
        }
    }, new Action1<Throwable>() {
        @Override
        public void call(Throwable throwable) {
            System.out.println("onError--> " + throwable.getMessage());
        }
    }, new Action0() {
        @Override
        public void call() {
            System.out.println("onComplete");
        }
    });
日志:
onNext--> [1, 2, 3]
onNext--> [4, 5, 6]
onNext--> [7, 8, 9]
onNext--> [10]
onComplete

GroupBy

GroupBy操作符將原始Observable發射的數據按照key來拆分成一些小的Observable,然后這些小的Observable分別發射其所包含的的數據。

               Observable.just(1, 2, 3, 4, 5, 6)
                .groupBy(new Func1<Integer, Boolean>() {
                    @Override
                    public Boolean call(Integer integer) {
                        return integer % 2 == 0;
                    }
                })
                .subscribe(new Action1<GroupedObservable<Boolean, Integer>>() {
                    @Override
                    public void call(final GroupedObservable<Boolean, Integer> observable) {
                        //toList方法轉換為Observable<List<T>>
                        observable.toList().subscribe(new Action1<List<Integer>>() {
                            @Override
                            public void call(List<Integer> integers) {
                                Log.d(TAG, "key=" + observable.getKey() + ",values=" + integers);
                                //key=false,values=[1, 3, 5]
                                //key=true,values=[2, 4, 6]
                            }
                        });
                    }
                });

Filter

Filter返回滿足過濾條件的數據。

        Observable.from(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9})
                .filter(new Func1<Integer, Boolean>() {
                    @Override
                    public Boolean call(Integer integer) {
                        return integer < 5;
                    }
                })
                .subscribe(new Action1<Integer>() {
                    @Override
                    public void call(Integer integer) {
                        Log.d(TAG, "integer=" + integer); //1,2,3,4

                    }
                });

First

First操作符返回第一條數據或者返回滿足條件的第一條數據。

 Observable.from(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9})
                .first()
                .subscribe(new Action1<Integer>() {
                    @Override
                    public void call(Integer integer) {
                        Log.d(TAG, "integer=" + integer); //1 返回第一條數據 

                    }
                });

Observable.from(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9})
                .first(new Func1<Integer, Boolean>() {
                    @Override
                    public Boolean call(Integer integer) {
                        return integer > 3;
                    }
                })
                .subscribe(new Action1<Integer>() {
                    @Override
                    public void call(Integer integer) {
                        Log.d(TAG, "integer=" + integer); //4 返回滿足條件的第一條數據

                    }
                });

Last

Last操作符返回最后一條數據或者滿足條件的最后一條數據。

Skip

Skip操作符將源Observable發射的數據過濾掉前n項。

    Observable.from(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9})
                .skip(6)
                .subscribe(new Action1<Integer>() {
                    @Override
                    public void call(Integer integer) {
                        Log.d(TAG, "integer=" + integer); //7,8,9
                    }
                });

Take

Take操作符只取前n項。

        Observable.from(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9})
                .take(2)
                .subscribe(new Action1<Integer>() {
                    @Override
                    public void call(Integer integer) {
                        Log.d(TAG, "integer=" + integer); //1,2
                    }
                });
  • 說明:根據我的學習和研究,個人覺得filter、first、等操作符與map的用法類似,感覺都可以用map()自己封裝。

本文暫時總結這些,如果以后有總結,在更新。

關于線程控制,放在下篇講解。


歡迎繼續收看:RxJava入門與提高-線程控制Scheduler篇(4)

作者:ZhangYushui
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容