RxJava 學習筆記(六) --- Transforming 變換操作符

1. Map —> 對序列的每一項都應用一個函數來變換Observable發射的數據序列

            enter image description here

示例代碼:

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

輸出

next:3 
next:6 
next:9 
next:12 
next:15 
next:18

2. Cast —> 操作符將原始Observable發射的每一項數據都強制轉換爲一個指定的類型,然後再發射數據,它是map的一個特殊版本。

            enter image description here

cast操作符類似於map操作符,不同的地方在於map操作符可以通過自定義規則,把一個值A1變成另一個值A2A1A2的類型可以一樣也可以不一樣;而cast操作符主要是做類型轉換的,傳入參數爲類型class,如果源Observable產生的結果不能轉成指定的class,則會拋出ClassCastException運行時異常。

示例代碼:

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);
            }
        });

輸出

next:1 
next:2 
next:3 
next:4 
next:5 
next:6

3. FlatMap —> 將Observable發射的數據集合變換爲Observables集合,然後將這些Observable發射的數據平坦化的放進一個單獨的Observable

FlatMap將一個發射數據的Observable變換爲多個Observables,然後將它們發射的數據合併後放進一個單獨的Observable
            enter image description here

FlatMap操作符使用一個指定的函數對原始Observable發射的每一項數據執行變換操作,這個函數返回一個本身也發射數據的Observable,然後FlatMap合併這些Observables發射的數據,最後將合併後的結果當做它自己的數據序列發射。

這個方法是很有用的,例如,當你有一個這樣的Observable:它發射一個數據序列,這些數據本身包含Observable成員或者可以變換爲Observable,因此你可以創建一個新的Observable發射這些次級Observable發射的數據的完整集合。

Student[] students = ...;
Subscriber<Course> subscriber = new Subscriber<Course>() {
    @Override
    public void onNext(Course course) {
        Log.d(tag, course.getName());
    }
    ...
};
Observable.from(students)
    .flatMap(new Func1<Student, Observable<Course>>() {
        @Override
        public Observable<Course> call(Student student) {
            return Observable.from(student.getCourses());
        }
    })
    .subscribe(subscriber);

注意:FlatMap對這些Observables發射的數據做的是合併(merge)操作,因此它們可能是交錯的。

在許多語言特定的實現中,還有一個操作符不會讓變換後的Observables發射的數據交錯,它按照嚴格的順序發射這些數據,這個操作符通常被叫作ConcatMap或者類似的名字。

注意:如果任何一個通過這個flatMap操作產生的單獨的Observable調用onError異常終止了,這個Observable自身會立即調用onError並終止。

這個操作符有一個接受額外的int參數的一個變體。這個參數設置flatMap從原來的Observable映射Observables的最大同時訂閱數。當達到這個限制時,它會等待其中一個終止然後再訂閱另一個。

4. ConcatMap —> 它類似於最簡單版本的flatMap,但是它按次序連接而不是合併那些生成的Observables,然後產生自己的數據序列。

concatMap()函數解決了flatMap()的交叉問題,提供了一種能夠把發射的值連續在一起的鋪平函數,而不是合併它們

            enter image description here

看這篇文章flatMap()vs concatMap ,點我點我

5. SwitchMap —> 將Observable發射的數據集合變換爲Observables集合,然後只發射這些Observables最近發射的數據

它和flatMap很像,除了一點:當原始Observable發射一個新的數據(Observable)時,它將取消訂閱並停止監視產生執之前那個數據的Observable,只監視當前這一個。

enter image description here

示例代碼:

Observable.just("A", "B", "C", "D", "E").switchMap(new Func1<String, Observable<String>>() {
            @Override
            public Observable<String> call(String s) {
                return Observable.just(s).subscribeOn(Schedulers.newThread());
            }
        }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<String>() {
            @Override
            public void onCompleted() {
                System.out.println("------>onCompleted()");
            }

            @Override
            public void onError(Throwable e) {
                System.out.println("------>onError()" + e);
            }

            @Override
            public void onNext(String s) {
                System.out.println("------>onNext:" + s);
            }
        });
    }

輸出

------>onNext:E
------>onCompleted()

6. Scan —> 連續地對數據序列的每一項應用一個函數,然後連續發射結果

Scan操作符對原始Observable發射的第一項數據應用一個函數,然後將那個函數的結果作爲自己的第一項數據發射。它將函數的結果同第二項數據一起填充給這個函數來產生它自己的第二項數據。它持續進行這個過程來產生剩餘的數據序列。這個操作符在某些情況下被叫做accumulator

            enter image description here

示例代碼:

Observable.just(1, 2, 3, 4, 5)
                .scan(new Func2<Integer, Integer, Integer>() {
                    @Override
                    public Integer call(Integer sum, Integer item) {
                        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.");
            }
        });

輸出:

Next: 1
Next: 3
Next: 6
Next: 10
Next: 15
Sequence complete.

有一個scan操作符的變體,你可以傳遞一個種子值給累加器函數的第一次調用(Observable發射的第一項數據)。如果你使用這個版本,scan將發射種子值作爲自己的第一項數據。注意:傳遞null作爲種子值與不傳遞是不同的,null種子值是合法的。

            enter image description here

示例代碼

Observable.just(1,2,3,4,5).scan(100, new Func2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer integer, Integer integer2) {
                return integer + integer2;
            }
        }).subscribe(new Subscriber<Integer>() {
            @Override
            public void onCompleted() {
                System.out.println("Sequence complete.");
            }

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

            @Override
            public void onNext(Integer integer) {
                System.out.println("Next: " + integer);
            }
        });

輸出

Next: 100
Next: 101
Next: 103
Next: 106
Next: 110
Next: 115

7. Buffer —> 它定期從Observable收集數據到一個集合,然後把這些數據集合打包發射,而不是一次發射一個

            enter image description here

Buffer操作符將一個Observable變換爲另一個,原來的Observable正常發射數據,變換產生的Observable發射這些數據的緩存集合。Buffer操作符在很多語言特定的實現中有很多種變體,它們在如何緩存這個問題上存在區別。

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

Window操作符與Buffer類似,但是它在發射之前把收集到的數據放進單獨的Observable,而不是放進一個數據結構。

RxJava中有許多Buffer的變體:

buffer(count)

            enter image description here

buffer(count)以列表(List)的形式發射非重疊的緩存,每一個緩存至多包含來自原始Observablecount項數據(最後發射的列表數據可能少於count項)

示例代碼

Observable.range(1,5).buffer(2).subscribe(new Observer<List<Integer>>() {
            @Override
            public void onCompleted() {
                System.out.println("-----------------onCompleted:");
            }

            @Override
            public void onError(Throwable e) {
                System.out.println("----------------->onError:");
            }

            @Override
            public void onNext(List<Integer> strings) {
                System.out.println("----------------->onNext:" + strings);
            }
        });

輸出

----------------->onNext:[1, 2]
----------------->onNext:[3, 4]
----------------->onNext:[5]
-----------------onCompleted:

buffer(count, skip)

            enter image description here

buffer(count, skip)從原始Observable的第一項數據開始創建新的緩存,此後每當收到skip項數據,用count項數據填充緩存:開頭的一項和後續的count-1項,它以列表(List)的形式發射緩存,取決於countskip的值,這些緩存可能會有重疊部分(比如skip < count時),也可能會有間隙(比如skip > count時)。

示例代碼: 取4個數 每次跳過2

Observable.range(1, 5).buffer(4, 2).subscribe(new Observer<List<Integer>>() {
            @Override
            public void onCompleted() {
                System.out.println("-----------------onCompleted:");
            }

            @Override
            public void onError(Throwable e) {
                System.out.println("----------------->onError:");
            }

            @Override
            public void onNext(List<Integer> strings) {
                System.out.println("----------------->onNext:" + strings);
            }
        });

輸出:

----------------->onNext:[1, 2, 3, 4]
----------------->onNext:[3, 4, 5]
----------------->onNext:[5]
-----------------onCompleted:

buffer(timespan, unit[, scheduler])

            enter image description here

buffer(timespan, unit)定期以List的形式發射新的數據,每個時間段,收集來自原始Observable的數據(從前面一個數據包裹之後,或者如果是第一個數據包裹,從有觀察者訂閱原來的Observale之後開始)。還有另一個版本的buffer接受一個Scheduler參數,默認情況下會使用computation調度器。

示例代碼:

    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//設置日期格式
    Observable.create(new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> subscriber) {

            if (subscriber.isUnsubscribed())
                return;

            try{

                while (true){
                    subscriber.onNext("數據:"+df.format(new Date()));
                    SystemClock.sleep(2000);
                }

            }catch (Exception e){
                subscriber.onError(e);
            }

        }
    }).buffer(3,TimeUnit.SECONDS).subscribe(new Action1<List<String>>() {
        @Override
        public void call(List<String> strings) {
            String s ="";
            for (int i = 0 ; i < strings.size(); i++){

                    s = s+ ","+ strings.get(i);

            }
            System.out.println(s);
        }
    });

輸出

,數據:2016-07-07 10:30:27,數據:2016-07-07 10:30:29
,數據:2016-07-07 10:30:31
,數據:2016-07-07 10:30:33,數據:2016-07-07 10:30:35
,數據:2016-07-07 10:30:37
,數據:2016-07-07 10:30:39,數據:2016-07-07 10:30:41
,數據:2016-07-07 10:30:43

8. Window —> 定期將來自原始Observable的數據分解爲一個Observable窗口,發射這些窗口,而不是每次發射一項數據

WindowBuffer類似,但不是發射來自原始Observable的數據包,它發射的是Observables,這些Observables中的每一個都發射原始Observable數據的一個子集,最後發射一個onCompleted通知。

            enter image description here

示例代碼:

Observable.interval(1,TimeUnit.SECONDS).take(10).window(3,TimeUnit.SECONDS).subscribe(new Observer<Observable<Long>>() {  
            @Override  
            public void onCompleted() {  
                LogUtils.d("------>onCompleted()");  
            }  

            @Override  
            public void onError(Throwable e) {  
                LogUtils.d("------>onError()" + e);  
            }  

            @Override  
            public void onNext(Observable<Long> integerObservable) {  
                LogUtils.d("------->onNext()");  
                integerObservable.subscribe(new Action1<Long>() {  
                    @Override  
                    public void call(Long integer) {  
                        LogUtils.d("------>call():" + integer);  
                    }  
                });  
            }  
        });  

輸出:

I/System.out: ------>call():0
I/System.out: ------>call():1
I/System.out: ------->onNext()
I/System.out: ------>call():2
I/System.out: ------>call():3
I/System.out: ------>call():4
I/System.out: ------->onNext()
I/System.out: ------>call():5
I/System.out: ------>call():6
I/System.out: ------>call():7
I/System.out: ------->onNext()
I/System.out: ------>call():8
I/System.out: ------>call():9
I/System.out: ------>onCompleted()

9. GroupBy —> 將Observable分拆爲Observable集合,將原始Observable發射的數據按Key分組,每一個Observable發射一組不同的數據

            enter image description here

GroupBy操作符將原始Observable分拆爲一些Observables集合,它們中的每一個發射原始Observable數據序列的一個子序列。哪個數據項由哪一個Observable發射是由一個函數判定的,這個函數給每一項指定一個KeyKey相同的數據會被同一個Observable發射。

RxJava實現了groupBy操作符。它返回Observable的一個特殊子類GroupedObservable,實現了GroupedObservable接口的對象有一個額外的方法getKey,這個Key用於將數據分組到指定的Observable

有一個版本的groupBy允許你傳遞一個變換函數,這樣它可以在發射結果GroupedObservable之前改變數據項。

注意:groupBy將原始Observable分解爲一個發射多個GroupedObservableObservable,一旦有訂閱,每個GroupedObservable就開始緩存數據。因此,如果你忽略這些GroupedObservable中的任何一個,這個緩存可能形成一個潛在的內存泄露。因此,如果你不想觀察,也不要忽略GroupedObservable。你應該使用像take(0)這樣會丟棄自己的緩存的操作符。

如果你取消訂閱一個GroupedObservable,那個Observable將會終止。如果之後原始的Observable又發射了一個與這個ObservableKey匹配的數據,groupBy將會爲這個Key創建一個新的GroupedObservable

groupBy默認不在任何特定的調度器上執行。

示例代碼:

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);
                    }
                });
            }
        });

輸出:

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
發佈了34 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章