RxJava使用詳解--轉換操作符

RxJava使用詳解系列文章

RxJava使用詳解--創建操作符

RxJava使用詳解--過濾操作符

詳細的例子可以查看文章末尾的源碼


這篇文章主要將RxJava中常見 的轉換操作符。


1.Buffer():

定期收集Observable的數據放進一個數據包裹,然後發射這些數據包裹,而不是一次發射一個值。Buffer操作符將一個Observable變換成另一個,原來的Observable正常發射數據,變換產生的Observable發射這些數據的緩存集合。如果原來的Observable發射了一個onError通知,buffer會立即傳遞這個通知,而不是首先發射緩存的數據,即使已經緩存了數據。buffer有很多的變體,有多個重載方法。


buffer(count):以列表(List集合)的形式發射非重疊(不是指沒有重複元素,而是集合的界限)的緩存數據,每一個緩存(List集合)最多包含來自原始Observable的count個數據(最後發射的列表List可能少於count個,最後一個list可能沒有count個元素),此處的count相當於集合的size()
//1.buffer(count):以列表(List集合)的形式發射非重疊(不是指沒有重複元素,而是集合的界限)的緩存數據,每一個緩存(List集合)最多包含來自原始Observable的count個數據(最後發射的列表List可能少於count個,最後一個list可能沒有count個元素),此處的count相當於集合的size()
System.out.println("buffer(count) ");
Observable.range(1, 6).buffer(2).subscribe(new Action1<List<Integer>>() {
    @Override
    public void call(List<Integer> integers) {
        System.out.println("onNnext:" + integers.toString());
    }
});
/**
 * 2.buffer(count,skip) :有這麼一種情況 buffer(count) 等價於 buffer(count,count).
 * 詳細說一下: buffer(2)輸出爲 【1,2】【3,4】【5,6】 那麼buffer(2,3)就要這麼算:首先從第一項開始緩存2個數據,【1,2】,此時的skip=3,意思是第二個集合的第一項是第skip+1項的數據,也就是第四個,集合長度是2,結果就是【4,5】,
 * 此時可用的數據是4,5,6,再計算第三個集合的時候,第三個集合的第一項就應該是第skip+1項的數據,然而沒有第四個數據,就沒有第三個集合了。
 */
System.out.println("- - - - - - - - - - - - - - - - - - - - - ");
System.out.println("buffer(count,skip) ");
Observable.range(1, 6).buffer(3, 2).subscribe(new Action1<List<Integer>>() {
    @Override
    public void call(List<Integer> integers) {
        System.out.println("onNnext:" + integers.toString());
    }
});

輸出結果:

buffer(count)
onNnext:[1, 2]
onNnext:[3, 4]
onNnext:[5, 6]
onCompleted:完成
- - - - - - - - - - - - - - - - - - - - -
buffer(count,skip)
[1, 2, 3]
[3, 4, 5]
[5, 6]
onCompleted:完成


2.map() flatMap()

map():對Observable發射的每一項數據使用函數執行變換操作,然後在發射出去。返回的對象可以隨便指定,可以實現一對一的轉換
flatmap():使用指定函數對原始的Observable發射的每一項數據執行變換操作,返回一個Observable,這個Observable也可以發射數據,可以實現一對多轉換,可能還會出現次序出錯的問題,使用的merge,不能保證原來的順序
相同點:都是講傳入的參數轉化之後返回另一個對象,不同點:flatmap()返回的是Observable對象,
flatMap() 的原理是這樣的:1. 使用傳入的事件對象創建一個 Observable 對象;2. 並不發送這個 Observable, 而是將它激活,於是它開始發送事件;3. 每一個創建出來的 Observable 發送的事件,都被匯入同一個 Observable ,而這個 Observable 負責將這些事件統一交給 Subscriber 的回調方法。這三個步驟,把事件拆成了兩級,通過一組新創建的 Observable 將初始的對象『鋪平』之後通過統一路徑分發了下去。而這個『鋪平』就是 flatMap() 所謂的 flat。




定義一個學生類
class Student{
    private String name;
    private List<String> course = new ArrayList<>();
.....省略
}


輸出結果:

onNext:數學  所在線程:main
onNext:語文  所在線程:main
onNext:英語  所在線程:main
- - - - - - - - - - - -
小明
onNext:小剛 所在線程:main


3.concatMap()

類似於最簡單版本的flatMap,唯一不同是concatMap是按次序連接而不是合併那那些生成的Observables,然後產生自己的數據序列,concatMap操作符在處理產生的Observable時,採用的是“concat”連接的方式,不是“merge”,如果需求是要保證順序的話建議用concatMap()


輸出結果:

onNext:1 所在線程:main
onNext:2 所在線程:main
onNext:3 所在線程:main
onNext:4 所在線程:main
onNext:5 所在線程:main
onNext:6 所在線程:main


4.switchMap():

類似於flatMap(),有一點不同,只監視當前Observable,或者是最後發射的數據。需要延時執行,當是延時是0 的時候回發射第一個數據,延時是大於0的任何值都是發射最後一個值

有一個使用場景:搜索的時候,在輸入完畢之後再去請求數據,大可不必沒每輸入一個都要發送請求。

Observable.just(10, 20, 30).switchMap(new Func1<Integer, Observable<Integer>>() {
    @Override
    public Observable<Integer> call(Integer integer) {

        return Observable.just(integer).delay(0, TimeUnit.MILLISECONDS);
    }
}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<Integer>() {
    @Override
    public void call(Integer integer) {
        System.out.println("switchMap onNext:" + integer);
    }
});

輸出結果:

12-18 15:23:08.180 27918-27918/? I/System.out: switchMap onNext:10
12-18 15:23:08.181 27918-27918/? I/System.out: switchMap onNext:30


5.cast():

類似於map操作符,map()操作符可以自定義規則,將值A1編程A2,A1和A2的類型可以一樣也可以不一樣;而cast()操作符主要是做類型轉換的,

傳入參數的類型class,如果Observable發射的結果不能轉成指定的class,就會拋出ClassCastException運行異常

Observable.just("蘋果","香蕉").cast(String.class).subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
        System.out.println("cast onNext " + s);
    }
});

輸出結果:

cast onNext 蘋果
cast onNext 香蕉

6.groupBy():

對原來Observable發射的數據進行分組,形成一個GroupedObservable的結果集,GroupedObservable.getKey()可以獲取鍵,

注意:由於結果集中的GroupedObservable是把分組結果緩存起來,如果對每一個GroupedObservable不進行處理(既不訂閱也不對其進行別的操作符運算)就有可能出現內存泄漏,所以如果不對GroupedObservable進行處理,最好對其使用操作符take(0)處理


Observable.just(1,2,3,4).take(4).groupBy(new Func1<Integer, String>() {
    @Override
    public String call(Integer value) {
        return value < 3 ? "第一組":"第二組"; //這裏執行分組的函數
    }
}).subscribe(new Action1<GroupedObservable<String, Integer>>() {
    @Override
    public void call(final GroupedObservable<String, Integer> result) {
        result.subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer value) {
                System.out.println("GroupBy  onNext " + result.getKey() +":"+ value);
            }
        });
    }
});

輸出結果:

12-18 15:28:21.825 1776-1776/? I/System.out: GroupBy  onNext 第一組:1
12-18 15:28:21.825 1776-1776/? I/System.out: GroupBy  onNext 第一組:2
12-18 15:28:21.825 1776-1776/? I/System.out: GroupBy  onNext 第二組:3
12-18 15:28:21.825 1776-1776/? I/System.out: GroupBy  onNext 第二組:4


7.scan():

通過遍歷原來Observable產生的結果,每一次對每一個結果按照指定規則進行運算,

計算的結果作爲下一個迭代項參數,每一次都會把迭代項數據發射給訂閱者,這裏result就是那個迭代項,scan()操作符有個變體,可以設置初始值,下方就是講初始值設置成了6,發射的第一個值就是6而不是1

Observable.just(1,2,3,4,5).scan(6,new Func2<Integer, Integer, Integer>() {
    @Override
    public Integer call(Integer result, Integer item2) {
        return result + item2 ;//result是上一次計算的結果
    }
}).subscribe(new Action1<Integer>() {
    @Override
    public void call(Integer integer) {
        System.out.println("scan onNext " + integer);
    }
});

輸出結果:

scan onNext 6
scan onNext 7
scan onNext 9
scan onNext 12
scan onNext 16
scan onNext 21


8.window():

類似於buffer()操作符,區別在於buffer操作符產生的結果是List緩存,而window()操作符產生的是一個Observable對象,訂閱者可以對這個產生的Observable對象重新進行訂閱處理,window操作符有很多重載方法

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

輸出結果:

12-18 15:38:24.100 12515-12553/com.dingmouren.rxjavademo I/System.out: window onNext 0
12-18 15:38:25.100 12515-12553/com.dingmouren.rxjavademo I/System.out: window onNext 1
12-18 15:38:26.099 12515-12553/com.dingmouren.rxjavademo I/System.out: window onNext 2
12-18 15:38:27.099 12515-12553/com.dingmouren.rxjavademo I/System.out: window onNext 3
12-18 15:38:28.099 12515-12553/com.dingmouren.rxjavademo I/System.out: window onNext 4
12-18 15:38:29.099 12515-12553/com.dingmouren.rxjavademo I/System.out: window onNext 5


更多詳細內容,可以查看源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章