一. 操作符
1. create
create操作符主要用于產生一個Obserable被觀察者對象(發射器)。
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
mRxOperatorsText.append("Observable emit 1" + "\n");
Log.e(TAG, "Observable emit 1" + "\n");
e.onNext(1);
mRxOperatorsText.append("Observable emit 2" + "\n");
Log.e(TAG, "Observable emit 2" + "\n");
e.onNext(2);
mRxOperatorsText.append("Observable emit 3" + "\n");
Log.e(TAG, "Observable emit 3" + "\n");
e.onNext(3);
e.onComplete();
mRxOperatorsText.append("Observable emit 4" + "\n");
Log.e(TAG, "Observable emit 4" + "\n" );
e.onNext(4);
}
}).subscribe(new Observer<Integer>() {
private int i;
private Disposable mDisposable;
@Override
public void onSubscribe(@NonNull Disposable d) {
mRxOperatorsText.append("onSubscribe : " + d.isDisposed() + "\n");
Log.e(TAG, "onSubscribe : " + d.isDisposed() + "\n" );
mDisposable = d;
}
@Override
public void onNext(@NonNull Integer integer) {
mRxOperatorsText.append("onNext : value : " + integer + "\n");
Log.e(TAG, "onNext : value : " + integer + "\n" );
i++;
if (i == 2) {
// 在RxJava 2.x 中,新增的Disposable可以做到切斷的操作,讓Observer觀察者不再接收上游事件
mDisposable.dispose();
mRxOperatorsText.append("onNext : isDisposable : " + mDisposable.isDisposed() + "\n");
Log.e(TAG, "onNext : isDisposable : " + mDisposable.isDisposed() + "\n");
}
}
@Override
public void onError(@NonNull Throwable e) {
mRxOperatorsText.append("onError : value : " + e.getMessage() + "\n");
Log.e(TAG, "onError : value : " + e.getMessage() + "\n" );
}
@Override
public void onComplete() {
mRxOperatorsText.append("onComplete" + "\n");
Log.e(TAG, "onComplete" + "\n" );
}
});
輸出:
需要注意的幾點是:
- 在發射事件中,我們在發射了數值3之后,直接調用了e.onComlete(),雖然無法接收事件,但發送事件還是繼續的。
- 另外一個值得注意的點是,在RxJava 2.x中,可以看到發射事件方法相比1.x多了一個throws Excetion,意味著我們做一些特定操作再也不用try-catch了。
- 并且2.x 中有一個Disposable概念,這個東西可以直接調用切斷,可以看到,當它的isDisposed()返回為false的時候,接收器能正常接收事件,但當其為true的時候,接收器停止了接收。所以可以通過此參數動態控制接收事件了。
2. map
map基本算是RxJava中一個最簡單的操作符了,熟悉RxJava 1.x的知道,它的作用是對發射時間發送的每一個事件應用一個函數,是的每一個事件都按照指定的函數去變化,而在2.x中它的作用幾乎一致。
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onNext(3);
}
}).map(new Function<Integer, String>() {
@Override
public String apply(@NonNull Integer integer) throws Exception {
return "This is result " + integer;
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
mRxOperatorsText.append("accept : " + s +"\n");
Log.e(TAG, "accept : " + s +"\n" );
}
});
輸出:
是的,map基本作用就是將一個Observable通過某種函數關系,轉換為另一種Observable,上面例子中就是把我們的Integer數據變成了String類型。從Log日志顯而易見。
3. zip
zip專用于合并事件,該合并不是連接(連接操作符后面會說),而是兩兩配對,也就意味著,最終配對出的Observable發射事件數目只和少的那個相同。
Observable.zip(getStringObservable(), getIntegerObservable(), new BiFunction<String, Integer, String>() {
@Override
public String apply(@NonNull String s, @NonNull Integer integer) throws Exception {
return s + integer;
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
mRxOperatorsText.append("zip : accept : " + s + "\n");
Log.e(TAG, "zip : accept : " + s + "\n");
}
});
private Observable<String> getStringObservable() {
return Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
if (!e.isDisposed()) {
e.onNext("A");
mRxOperatorsText.append("String emit : A \n");
Log.e(TAG, "String emit : A \n");
e.onNext("B");
mRxOperatorsText.append("String emit : B \n");
Log.e(TAG, "String emit : B \n");
e.onNext("C");
mRxOperatorsText.append("String emit : C \n");
Log.e(TAG, "String emit : C \n");
}
}
});
}
private Observable<Integer> getIntegerObservable() {
return Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
if (!e.isDisposed()) {
e.onNext(1);
mRxOperatorsText.append("Integer emit : 1 \n");
Log.e(TAG, "Integer emit : 1 \n");
e.onNext(2);
mRxOperatorsText.append("Integer emit : 2 \n");
Log.e(TAG, "Integer emit : 2 \n");
e.onNext(3);
mRxOperatorsText.append("Integer emit : 3 \n");
Log.e(TAG, "Integer emit : 3 \n");
e.onNext(4);
mRxOperatorsText.append("Integer emit : 4 \n");
Log.e(TAG, "Integer emit : 4 \n");
e.onNext(5);
mRxOperatorsText.append("Integer emit : 5 \n");
Log.e(TAG, "Integer emit : 5 \n");
}
}
});
}
輸出:
需要注意的是:
- zip 組合事件的過程就是分別從發射器A和發射器B各取出一個事件來組合,并且一個事件只能被使用一次,組合的順序是嚴格按照事件發送的順序來進行的,所以上面截圖中,可以看到,1永遠是和A 結合的,2永遠是和B結合的。
- 最終接收器收到的事件數量是和發送器發送事件最少的那個發送器的發送事件數目相同,所以如截圖中,4和5很孤單,沒有人愿意和它交往,孤獨終老的單身狗。
4. concat
對于單一的把兩個發射器連接成一個發射器,雖然 zip 不能完成,但我們還是可以自力更生,官方提供的 concat 讓我們的問題得到了完美解決。
Observable.concat(Observable.just(1,2,3), Observable.just(4,5,6))
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("concat : "+ integer + "\n");
Log.e(TAG, "concat : "+ integer + "\n" );
}
});
輸出:
如圖,可以看到。發射器B把自己的三個孩子送給了發射器A,讓他們組合成了一個新的發射器,非常懂事的孩子,有條不紊的排序接收。
5. flatMap
FlatMap 是一個很有趣的東西,我堅信你在實際開發中會經常用到。它可以把一個發射器Observable 通過某種方法轉換為多個Observables,然后再把這些分散的Observables裝進一個單一的發射器Observable。但有個需要注意的是,flatMap并不能保證事件的順序,如果需要保證,需要用到我們下面要講的ConcatMap。
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onNext(3);
}
}).flatMap(new Function<Integer, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(@NonNull Integer integer) throws Exception {
List<String> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add("I am value " + integer);
}
int delayTime = (int) (1 + Math.random() * 10);
return Observable.fromIterable(list).delay(delayTime, TimeUnit.MILLISECONDS);
}
}).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.e(TAG, "flatMap : accept : " + s + "\n");
mRxOperatorsText.append("flatMap : accept : " + s + "\n");
}
});
輸出:
一切都如我們預期中的有意思,為了區分concatMap(下一個會講),我在代碼中特意動了一點小手腳,我采用一個隨機數,生成一個時間,然后通過delay(后面會講)操作符,做一個小延時操作,而查看Log日志也確認驗證了我們上面的說法,它是無序的。
6. concatMap
上面其實就說了,concatMap 與 FlatMap 的唯一區別就是 concatMap 保證了順序,所以,我們就直接把 flatMap 替換為 concatMap 驗證吧。
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onNext(3);
}
}).concatMap(new Function<Integer, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(@NonNull Integer integer) throws Exception {
List<String> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add("I am value " + integer);
}
int delayTime = (int) (1 + Math.random() * 10);
return Observable.fromIterable(list).delay(delayTime, TimeUnit.MILLISECONDS);
}
}).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.e(TAG, "flatMap : accept : " + s + "\n");
mRxOperatorsText.append("flatMap : accept : " + s + "\n");
}
});
輸出:
7. distinct
這個操作符非常的簡單、通俗、易懂,就是簡單的去重嘛,我甚至都不想貼代碼,但人嘛,總得持之以恒。
Observable.just(1, 1, 1, 2, 2, 3, 4, 5)
.distinct()
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("distinct : " + integer + "\n");
Log.e(TAG, "distinct : " + integer + "\n");
}
});
輸出:
Log 日志顯而易見,我們在經過dinstinct() 后接收器接收到的事件只有1,2,3,4,5了。
8. Filter
信我,Filter 你會很常用的,它的作用也很簡單,過濾器嘛。可以接受一個參數,讓其過濾掉不符合我們條件的值
Observable.just(1, 20, 65, -5, 7, 19)
.filter(new Predicate<Integer>() {
@Override
public boolean test(@NonNull Integer integer) throws Exception {
return integer >= 10;
}
}).subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("filter : " + integer + "\n");
Log.e(TAG, "filter : " + integer + "\n");
}
});
輸出:
可以看到,我們過濾器舍去了小于10的值,所以最好的輸出只有20,65,19。
9. buffer
buffer 操作符接受兩個參數,buffef(count,skip),作用是將 Observable 中的數據按 skip (步長) 分成最大不超過 count 的 buffer ,然后生成一個 Observable 。也許你還不太理解,我們可以通過我們的示例圖和示例代碼來進一步深化它。
Observable.just(1, 2, 3, 4, 5)
.buffer(3, 2)
.subscribe(new Consumer<List<Integer>>() {
@Override
public void accept(@NonNull List<Integer> integers) throws Exception {
mRxOperatorsText.append("buffer size : " + integers.size() + "\n");
Log.e(TAG, "buffer size : " + integers.size() + "\n");
mRxOperatorsText.append("buffer value : ");
Log.e(TAG, "buffer value : " );
for (Integer i : integers) {
mRxOperatorsText.append(i + "");
Log.e(TAG, i + "");
}
mRxOperatorsText.append("\n");
Log.e(TAG, "\n");
}
});
輸出:
如圖,我們把1,2,3,4,5依次發射出來,經過buffer 操作符,其中參數 skip 為3, count 為2,而我們的輸出 依次是 123,345,5。顯而易見,我們 buffer 的第一個參數是count,代表最大取值,在事件足夠的時候,一般都是取count個值,然后每天跳過skip個事件。其實看 Log 日志,我相信大家都明白了。
10. timer
timer 很有意思,相當于一個定時任務。在1.x 中它還可以執行間隔邏輯,但在2.x中此功能被交給了 interval,下一個會介紹。但需要注意的是,timer 和 interval 均默認在新線程。
mRxOperatorsText.append("timer start : " + TimeUtil.getNowStrTime() + "\n");
Log.e(TAG, "timer start : " + TimeUtil.getNowStrTime() + "\n");
Observable.timer(2, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) // timer 默認在新線程,所以需要切換回主線程
.subscribe(new Consumer<Long>() {
@Override
public void accept(@NonNull Long aLong) throws Exception {
mRxOperatorsText.append("timer :" + aLong + " at " + TimeUtil.getNowStrTime() + "\n");
Log.e(TAG, "timer :" + aLong + " at " + TimeUtil.getNowStrTime() + "\n");
}
});
輸出:
顯而易見,當我們兩次點擊按鈕觸發這個事件的時候,接收被延遲了2秒。
11. interval
如同我們上面可說,interval 操作符用于間隔時間執行某個操作,其接受三個參數,分別是第一次發送延遲,間隔時間,時間單位。
mRxOperatorsText.append("interval start : " + TimeUtil.getNowStrTime() + "\n");
Log.e(TAG, "interval start : " + TimeUtil.getNowStrTime() + "\n");
Observable.interval(3,2, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) // 由于interval默認在新線程,所以我們應該切回主線程
.subscribe(new Consumer<Long>() {
@Override
public void accept(@NonNull Long aLong) throws Exception {
mRxOperatorsText.append("interval :" + aLong + " at " + TimeUtil.getNowStrTime() + "\n");
Log.e(TAG, "interval :" + aLong + " at " + TimeUtil.getNowStrTime() + "\n");
}
});
輸出:
如同 Log 日志一樣,第一次延遲了3秒后接收到,后面每次間隔了2秒。
然而,心細的小伙伴可能會發現,由于我們這個是間隔執行,所以當我們的Activity都銷毀的時候,實際上這個操作還依然在進行,所以,我們得花點小心思讓我們在不需要它的時候干掉它。查看源碼發現,我們subscribe(Cousumer<? super T> onNext)返回的是Disposable,我們可以在這上面做文章。
@Override
protected void doSomething() {
mRxOperatorsText.append("interval start : " + TimeUtil.getNowStrTime() + "\n");
Log.e(TAG, "interval start : " + TimeUtil.getNowStrTime() + "\n");
mDisposable = Observable.interval(3, 2, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) // 由于interval默認在新線程,所以我們應該切回主線程
.subscribe(new Consumer<Long>() {
@Override
public void accept(@NonNull Long aLong) throws Exception {
mRxOperatorsText.append("interval :" + aLong + " at " + TimeUtil.getNowStrTime() + "\n");
Log.e(TAG, "interval :" + aLong + " at " + TimeUtil.getNowStrTime() + "\n");
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mDisposable != null && !mDisposable.isDisposed()) {
mDisposable.dispose();
}
}
哈哈,再次驗證,解決了我們的疑惑。
12. doOnNext
其實覺得 doOnNext 應該不算一個操作符,但考慮到其常用性,我們還是咬咬牙將它放在了這里。它的作用是讓訂閱者在接收到數據之前干點有意思的事情。假如我們在獲取到數據之前想先保存一下它,無疑我們可以這樣實現。
Observable.just(1, 2, 3, 4)
.doOnNext(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("doOnNext 保存 " + integer + "成功" + "\n");
Log.e(TAG, "doOnNext 保存 " + integer + "成功" + "\n");
}
}).subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("doOnNext :" + integer + "\n");
Log.e(TAG, "doOnNext :" + integer + "\n");
}
});
輸出:
13. skip
skip 很有意思,其實作用就和字面意思一樣,接受一個 long 型參數 count ,代表跳過 count 個數目開始接收。
Observable.just(1,2,3,4,5)
.skip(2)
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("skip : "+integer + "\n");
Log.e(TAG, "skip : "+integer + "\n");
}
});
輸出:
14. take
take,接受一個 long 型參數 count ,代表至多接收 count 個數據。
Flowable.fromArray(1,2,3,4,5)
.take(2)
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("take : "+integer + "\n");
Log.e(TAG, "accept: take : "+integer + "\n" );
}
});
輸出:
15. just
just,沒什么好說的,其實在前面各種例子都說明了,就是一個簡單的發射器依次調用onNext()方法。
Observable.just("1", "2", "3")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
mRxOperatorsText.append("accept : onNext : " + s + "\n");
Log.e(TAG,"accept : onNext : " + s + "\n" );
}
});
輸出:
16. Single
顧名思義,Single 只會接收一個參數,而SingleObserver 只會調用onError 或者onSuccess。
Single.just(new Random().nextInt())
.subscribe(new SingleObserver<Integer>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onSuccess(@NonNull Integer integer) {
mRxOperatorsText.append("single : onSuccess : "+integer+"\n");
Log.e(TAG, "single : onSuccess : "+integer+"\n" );
}
@Override
public void onError(@NonNull Throwable e) {
mRxOperatorsText.append("single : onError : "+e.getMessage()+"\n");
Log.e(TAG, "single : onError : "+e.getMessage()+"\n");
}
});
輸出:
17. distinct
去重操作符,簡單的作用就是去重。
Observable.just(1, 1, 1, 2, 2, 3, 4, 5)
.distinct()
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("distinct : " + integer + "\n");
Log.e(TAG, "distinct : " + integer + "\n");
}
});
輸出:
很明顯,發射器發送的事件,在接收的時候被去重了。
18. debounce
去除發送頻率過快的項,看起來好像沒啥用處,但你信我,后面絕對有地方很有用武之地。
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Exception {
// send events with simulated time wait
emitter.onNext(1); // skip
Thread.sleep(400);
emitter.onNext(2); // deliver
Thread.sleep(505);
emitter.onNext(3); // skip
Thread.sleep(100);
emitter.onNext(4); // deliver
Thread.sleep(605);
emitter.onNext(5); // deliver
Thread.sleep(510);
emitter.onComplete();
}
}).debounce(500, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("debounce :" + integer + "\n");
Log.e(TAG,"debounce :" + integer + "\n");
}
});
輸出:
代碼很清晰,去除發送間隔時間小于500毫秒的發射事件,所以1 和 3 被去掉了。
19. defer
簡單地時候就是每次訂閱都會創建一個新的Observable,并且如果沒有被訂閱,就不會產生新的Observable
Observable<Integer> observable = Observable.defer(new Callable<ObservableSource<Integer>>() {
@Override
public ObservableSource<Integer> call() throws Exception {
return Observable.just(1, 2, 3);
}
});
observable.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull Integer integer) {
mRxOperatorsText.append("defer : " + integer + "\n");
Log.e(TAG, "defer : " + integer + "\n");
}
@Override
public void onError(@NonNull Throwable e) {
mRxOperatorsText.append("defer : onError : " + e.getMessage() + "\n");
Log.e(TAG, "defer : onError : " + e.getMessage() + "\n");
}
@Override
public void onComplete() {
mRxOperatorsText.append("defer : onComplete\n");
Log.e(TAG, "defer : onComplete\n");
}
});
輸出:
20. last
last 操作符僅取出可觀察到的最后一個值,或者是滿足某些條件的最后一項。
Observable.just(1, 2, 3)
.last(4)
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("last : " + integer + "\n");
Log.e(TAG, "last : " + integer + "\n");
}
});
輸出:
21. merge
merge 顧名思義,熟悉版本控制工具的你一定不會不知道 merge 命令,而在 Rx 操作符中,merge 的作用是把多個 Observable 結合起來,接受可變參數,也支持迭代器集合。注意它和 concat 的區別在于,不用等到 發射器 A 發送完所有的事件再進行發射器 B 的發送。
Observable.merge(Observable.just(1, 2), Observable.just(3, 4, 5))
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("merge :" + integer + "\n");
Log.e(TAG, "accept: merge :" + integer + "\n" );
}
});
輸出:
22. reduce
reduce 操作符每次用一個方法處理一個值,可以有一個 seed 作為初始值。
Observable.just(1, 2, 3)
.reduce(new BiFunction<Integer, Integer, Integer>() {
@Override
public Integer apply(@NonNull Integer integer, @NonNull Integer integer2) throws Exception {
return integer + integer2;
}
}).subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("reduce : " + integer + "\n");
Log.e(TAG, "accept: reduce : " + integer + "\n");
}
});
輸出:
可以看到,代碼中,我們中間采用 reduce ,支持一個 function 為兩數值相加,所以應該最后的值是:1 + 2 = 3 + 3 = 6 , 而Log 日志完美解決了我們的問題。
23. scan
scan 操作符作用和上面的 reduce 一致,唯一區別是 reduce 是個只追求結果的壞人,而 scan 會始終如一地把每一個步驟都輸出。
Observable.just(1, 2, 3)
.scan(new BiFunction<Integer, Integer, Integer>() {
@Override
public Integer apply(@NonNull Integer integer, @NonNull Integer integer2) throws Exception {
return integer + integer2;
}
}).subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
mRxOperatorsText.append("scan " + integer + "\n");
Log.e(TAG, "accept: scan " + integer + "\n");
}
});
輸出:
看日志,沒毛病。
24. window
按照實際劃分窗口,將數據發送給不同的Observable
mRxOperatorsText.append("window\n");
Log.e(TAG, "window\n");
Observable.interval(1, TimeUnit.SECONDS) // 間隔一秒發一次
.take(15) // 最多接收15個
.window(3, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Observable<Long>>() {
@Override
public void accept(@NonNull Observable<Long> longObservable) throws Exception {
mRxOperatorsText.append("Sub Divide begin...\n");
Log.e(TAG, "Sub Divide begin...\n");
longObservable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Long>() {
@Override
public void accept(@NonNull Long aLong) throws Exception {
mRxOperatorsText.append("Next:" + aLong + "\n");
Log.e(TAG, "Next:" + aLong + "\n");
}
});
}
});
輸出: