Rxjava學(xué)習(xí)總結(jié)

參考:
給 Android 開發(fā)者的 RxJava 詳解-扔物線
深入淺出RxJava

基礎(chǔ)

"a library for composing asynchronous and event-based programs using observable sequences for the Java VM" (一個在 Java VM 上使用可觀測的序列來組成==異步==的、基于事件的程序的庫)

采用函數(shù)響應(yīng)式編程的思想,使異步代碼更簡潔、邏輯更清晰,避免了令人頭痛的回調(diào)的嵌套、線程調(diào)度等問題。

RxJava 的觀察者模式

RxJava 有四個基本概念:Observable (被觀察者)、 Subscriber (觀察者)、 subscribe (訂閱)、事件。

Observable 和 Subscriber 通過 subscribe() 方法實(shí)現(xiàn)訂閱關(guān)系,從而 Observable 可以在需要的時(shí)候發(fā)出事件來通知 Subscriber。

與傳統(tǒng)觀察者模式的區(qū)別是:

  • 如果 Observerble 沒有任何的 Subscriber,那么這個 Observable 不會發(fā)出任何事件的。
  • RxJava 的事件回調(diào)方法除了普通事件 onNext() (相當(dāng)于 onClick() / onEvent())之外,還定義了兩個特殊的事件:onCompleted() 和 onError()。


  • onCompleted(): 事件隊(duì)列完結(jié)。當(dāng)事件流發(fā)送完畢時(shí),會觸發(fā) onCompleted() 方法。
  • onError(): 事件隊(duì)列異常。在事件處理過程中有異常拋出時(shí),onError() 會被觸發(fā),同時(shí)隊(duì)列自動終止,不允許再有事件發(fā)出。(RxJava 不僅把每個事件單獨(dú)處理,還會把它們看做一個隊(duì)列。)

基本實(shí)現(xiàn)

1.創(chuàng)建Observable

Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        subscriber.onNext("Hello");
        subscriber.onNext("Hi");
        subscriber.onNext("Aloha");
        subscriber.onCompleted();
    }
});

Observable 即被觀察者,它決定什么時(shí)候觸發(fā)事件以及觸發(fā)怎樣的事件。
這里,使用create()方法來創(chuàng)建一個 Observable,并定義事件觸發(fā)規(guī)則:觀察者Subscriber 將會被調(diào)用三次 onNext() 和一次 onCompleted()。這里傳入了一個 OnSubscribe 對象作為參數(shù)。OnSubscribe 會被存儲在返回的 Observable 對象中,它的作用相當(dāng)于一個計(jì)劃表,當(dāng) Observable 被訂閱的時(shí)候,OnSubscribe 的 call() 方法會自動被調(diào)用,事件序列就會依照設(shè)定依次觸發(fā)。這樣,由被觀察者調(diào)用了觀察者的回調(diào)方法,就實(shí)現(xiàn)了由被觀察者向觀察者的事件傳遞,即觀察者模式。

create()方法是 RxJava 最基本的創(chuàng)造事件序列的方法。基于這個方法, RxJava 還提供了一些方法用來快捷創(chuàng)建事件隊(duì)列,例如:

  • just(T...): 將傳入的參數(shù)依次發(fā)送出來。
  • from(T[]) / from(Iterable<? extends T>) : 將傳入的數(shù)組或 Iterable 拆分成具體對象后,依次發(fā)送出來。
Observable observable = Observable.just("Hello", "Hi", "Aloha");
String[] words = {"Hello", "Hi", "Aloha"};
Observable observable = Observable.from(words);

這兩段代碼與前面的創(chuàng)建方式等價(jià)。

2.創(chuàng)建Observer

Observer 即觀察者,它決定事件觸發(fā)的時(shí)候?qū)⒂性鯓拥男袨椤?br> RxJava 中的 Observer 接口:

public interface Observer<T> {

    void onCompleted();

    void onError(Throwable e);

    void onNext(T t);

}

此外,RxJava 還內(nèi)置了一個實(shí)現(xiàn)了 Observer、Subscription 的抽象類:Subscriber。
Subscriber 對 Observer 接口進(jìn)行了一些擴(kuò)展:

  1. onStart(): 在 subscribe 剛開始,而事件還未發(fā)送之前被調(diào)用,可以用于做一些準(zhǔn)備工作,例如數(shù)據(jù)的清零或重置。需要注意的是,如果對準(zhǔn)備工作的線程有要求(例如彈出一個顯示進(jìn)度的對話框,這必須在主線程執(zhí)行),onStart()就不適用了,因?yàn)樗偸窃?subscribe 所發(fā)生的線程被調(diào)用,而不能指定線程。要在指定的線程來做準(zhǔn)備工作,可以使用doOnSubscribe()方法。
  2. unsubscribe(): 這是 Subscriber 所實(shí)現(xiàn)的另一個接口 Subscription 的方法,用于取消訂閱。在這個方法被調(diào)用后,Subscriber 將不再接收事件。一般在這個方法調(diào)用前,可以使用isUnsubscribed()先判斷一下狀態(tài)。unsubscribe()這個方法很重要,因?yàn)樵?subscribe()之后, Observable 會持有 Subscriber 的引用,這個引用如果不能及時(shí)被釋放,將有內(nèi)存泄露的風(fēng)險(xiǎn)。所以最好保持一個原則:要在不再使用的時(shí)候盡快在合適的地方(例如onPause()``onStop()等方法中)調(diào)用 unsubscribe() 來解除引用關(guān)系,以避免內(nèi)存泄露的發(fā)生。

3.Subscribe

通過subscribe()方法將被觀察者和觀察者關(guān)聯(lián)起來:

observable.subscribe(subscriber);

內(nèi)部實(shí)現(xiàn)(僅核心代碼):

public Subscription subscribe(Subscriber subscriber) {
    subscriber.onStart();
    onSubscribe.call(subscriber);
    return subscriber;
}

subscribe()主要做了3件事:

  1. 調(diào)用Subscriber.onStart(),進(jìn)行訂閱前的初始化工作。
  2. 調(diào)用 Observable 中的 OnSubscribe.call(Subscriber)。事件發(fā)送的邏輯開始運(yùn)行。可以看到, Observable 并不是在創(chuàng)建的時(shí)候就立即開始發(fā)送事件,而是在它被訂閱的時(shí)候,即當(dāng)subscribe()方法執(zhí)行的時(shí)候,才開始發(fā)送事件。
  3. 將傳入的 Subscriber 作為 Subscription 返回,便于解除訂閱unsubscribe().
    subscribe過程圖

線程控制

默認(rèn)情況下,事件的發(fā)出和 消費(fèi)都是在同一個線程的。
要實(shí)現(xiàn)『后臺處理,前臺回調(diào)』的異步機(jī)制,可以使用subscribeOn()observeOn()兩個方法,結(jié)合Scheduler,來對線程進(jìn)行控制。

  • subscribeOn(): 指定subscribe()所發(fā)生的線程,即Observable.OnSubscribe被激活時(shí)所處的線程。或者叫做事件產(chǎn)生的線程。
  • observeOn(): 指定 Subscriber 所運(yùn)行的線程。或者叫做事件消費(fèi)的線程。

RxJava 內(nèi)置的 Scheduler:

  • Schedulers.immediate(): 直接在當(dāng)前線程運(yùn)行,這是默認(rèn)的 Scheduler。
  • Schedulers.newThread(): 總是啟用新線程,并在新線程執(zhí)行操作。
  • Schedulers.io(): I/O 操作(讀寫文件、讀寫數(shù)據(jù)庫、網(wǎng)絡(luò)信息交互等)。行為模式和 newThread() 差不多,區(qū)別在于 io() 的內(nèi)部實(shí)現(xiàn)是使用一個無數(shù)量上限的線程池,可以重用空閑的線程,因此多數(shù)情況下 io() 比 newThread() 更有效率。注意不要把計(jì)算工作放在 io() 線程中,以避免創(chuàng)建不必要的線程。
  • Schedulers.computation(): 用于 CPU 密集型計(jì)算,即不會被 I/O 等操作限制性能的操作,例如圖形的計(jì)算。這個 Scheduler 使用固定的線程池,大小為 CPU 核數(shù)。注意不要把 I/O 操作放在 computation() 中,否則 I/O 操作的等待時(shí)間會浪費(fèi) CPU。
  • AndroidSchedulers.mainThread():Android 主線程。

示例(適用于多數(shù)的 『后臺線程取數(shù)據(jù),主線程顯示』的程序策略):

Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 發(fā)生在 IO 線程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調(diào)發(fā)生在主線程
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer number) {
            Log.d(tag, "number:" + number);
        }
    });

線程的自用控制:
observeOn() 指定的是 Subscriber 的線程,而這個 Subscriber 并不一定是subscribe() 參數(shù)中的 Subscriber ,而是 observeOn() 執(zhí)行時(shí)的當(dāng)前 Observable 所對應(yīng)的Subscriber ,即它的直接下級 Subscriber 。換句話說,observeOn() 指定的是它之后的操作所在的線程。因此如果有多次切換線程的需求,只要在每個想要切換線程的位置調(diào)用一次 observeOn() 即可。

Observable.just(1, 2, 3, 4) // IO 線程,由 subscribeOn() 指定
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.newThread())
    .map(mapOperator) // 新線程,由 observeOn() 指定
    .observeOn(Schedulers.io())
    .map(mapOperator2) // IO 線程,由 observeOn() 指定
    .observeOn(AndroidSchedulers.mainThread) 
    .subscribe(subscriber);  // Android 主線程,由 observeOn() 指定

subscribeOn() 和 observeOn() 的內(nèi)部實(shí)現(xiàn),也是基于 lift() 方法。


subscribeOn( ) 原理圖

observeOn() 原理圖

從圖中可以看出,subscribeOn() 和 observeOn() 都做了線程切換的工作(圖中的 "schedule..." 部位)。不同的是, subscribeOn() 的線程切換發(fā)生在 OnSubscribe 中,即在它通知上一級 OnSubscribe 時(shí),這時(shí)事件還沒有開始發(fā)送,因此 subscribeOn() 的線程控制可以從事件發(fā)出的開端就造成影響;而 observeOn() 的線程切換則發(fā)生在它內(nèi)建的 Subscriber 中,即發(fā)生在它即將給下一級 Subscriber 發(fā)送事件時(shí),因此 observeOn() 控制的是它后面的線程。

多個 subscribeOn() 和 observeOn() 混合使用時(shí),線程調(diào)度的流程圖:


圖中共有 5 處含有對事件的操作。由圖中可以看出,①和②兩處受第一個 subscribeOn() 影響,運(yùn)行在紅色線程;③和④處受第一個 observeOn() 的影響,運(yùn)行在綠色線程;⑤處受第二個 onserveOn() 影響,運(yùn)行在紫色線程;而第二個 subscribeOn() ,由于在通知過程中線程就被第一個 subscribeOn() 截?cái)啵虼藢φ麄€流程并沒有任何影響。這里也就回答了前面的問題:==當(dāng)使用了多個 subscribeOn() 的時(shí)候,只有第一個 subscribeOn() 起作用。==

事件變換

RxJava 提供了對事件序列進(jìn)行變換的支持,這是它的核心功能之一,將事件序列中的對象或整個序列進(jìn)行加工處理,轉(zhuǎn)換成不同的事件或事件序列。

lift:針對事件項(xiàng)和事件序列的變換

map()flatMap()等變換都是基于同一個基礎(chǔ)的變換方法lift(Operator)的包裝。

lift()的內(nèi)部實(shí)現(xiàn)(僅核心代碼):

public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
    return Observable.create(new OnSubscribe<R>() {
        @Override
        public void call(Subscriber subscriber) {
            Subscriber newSubscriber = operator.call(subscriber);
            newSubscriber.onStart();
            onSubscribe.call(newSubscriber);
        }
    });
}

1.lift() 創(chuàng)建了一個 Observable 后,加上之前的原始 Observable,已經(jīng)有兩個 Observable 了;
2.而同樣地,新 Observable 里的新 OnSubscribe 加上之前的原始 Observable 中的原始 OnSubscribe,也就有了兩個 OnSubscribe;
3.當(dāng)用戶調(diào)用經(jīng)過 lift() 后的 Observable 的 subscribe() 的時(shí)候,使用的是 lift() 所返回的新的 Observable ,于是它所觸發(fā)的 onSubscribe.call(subscriber),也是用的新 Observable 中的新 OnSubscribe,即在 lift() 中生成的那個 OnSubscribe;
4.而這個新 OnSubscribe 的 call() 方法中的 onSubscribe ,就是指的原始 Observable 中的原始 OnSubscribe ,在這個 call() 方法里,新 OnSubscribe 利用 operator.call(subscriber) 生成了一個新的 Subscriber(Operator 就是在這里,通過自己的 call() 方法將新 Subscriber 和原始 Subscriber 進(jìn)行關(guān)聯(lián),并插入自己的『變換』代碼以實(shí)現(xiàn)變換),然后利用這個新 Subscriber 向原始 Observable 進(jìn)行訂閱。
這樣就實(shí)現(xiàn)了 lift() 過程,有點(diǎn)像一種代理機(jī)制,通過事件攔截和處理實(shí)現(xiàn)事件序列的變換。

簡而言之,在 Observable 執(zhí)行了 lift(Operator) 方法之后,會返回一個新的 Observable,這個新的 Observable 會像一個代理一樣,負(fù)責(zé)接收原始的 Observable 發(fā)出的事件,并在處理后發(fā)送給 Subscriber。

兩次和多次的 lift() 同理:

示例:將事件中的 Integer 對象轉(zhuǎn)換成 String

observable.lift(new Observable.Operator<String, Integer>() {
    @Override
    public Subscriber<? super Integer> call(final Subscriber<? super String> subscriber) {
        // 將事件序列中的 Integer 對象轉(zhuǎn)換為 String 對象
        return new Subscriber<Integer>() {
            @Override
            public void onNext(Integer integer) {
                subscriber.onNext("" + integer);
            }

            @Override
            public void onCompleted() {
                subscriber.onCompleted();
            }

            @Override
            public void onError(Throwable e) {
                subscriber.onError(e);
            }
        };
    }
});

compose: 對 Observable 整體的變換

它和 lift() 的區(qū)別在于, lift() 是針對事件項(xiàng)和事件序列的,而 compose() 是針對 Observable 自身進(jìn)行變換。

示例:
假設(shè)在程序中有多個 Observable ,并且他們都需要應(yīng)用一組相同的 lift() 變換。你可以這么寫:

observable1
    .lift1()
    .lift2()
    .lift3()
    .lift4()
    .subscribe(subscriber1);
observable2
    .lift1()
    .lift2()
    .lift3()
    .lift4()
    .subscribe(subscriber2);
observable3
    .lift1()
    .lift2()
    .lift3()
    .lift4()
    .subscribe(subscriber3);
observable4
    .lift1()
    .lift2()
    .lift3()
    .lift4()
    .subscribe(subscriber1);

這樣代碼復(fù)用性太差,于是改寫成:

private Observable liftAll(Observable observable) {
    return observable
        .lift1()
        .lift2()
        .lift3()
        .lift4();
}
...
liftAll(observable1).subscribe(subscriber1);
liftAll(observable2).subscribe(subscriber2);
liftAll(observable3).subscribe(subscriber3);
liftAll(observable4).subscribe(subscriber4);

可讀性、可維護(hù)性都提高了。可是 Observable 被一個方法包起來,如果后期需求變化,observable1在進(jìn)行l(wèi)iftAll()變換前需要先進(jìn)行l(wèi)ift5()變換,就打破了api的鏈?zhǔn)秸{(diào)用,這種方式對于 Observale 的靈活性增添了限制。此時(shí),就可以用 compose() 來解決:

public class LiftAllTransformer implements Observable.Transformer<Integer, String> {
    @Override
    public Observable<String> call(Observable<Integer> observable) {
        return observable
            .lift1()
            .lift2()
            .lift3()
            .lift4();
    }
}
...
Transformer liftAll = new LiftAllTransformer();
observable1.compose(liftAll).subscribe(subscriber1);
observable2.compose(liftAll).subscribe(subscriber2);
observable3.compose(liftAll).subscribe(subscriber3);
observable4.compose(liftAll).subscribe(subscriber4);

操作符

Rx中文文檔
操作符的使用示例

創(chuàng)建操作

  • Create — 通過調(diào)用觀察者的方法從頭創(chuàng)建一個Observable
  • Defer — 在觀察者訂閱之前不創(chuàng)建這個Observable,為每一個觀察者創(chuàng)建一個新的Observable
  • Empty/Never/Throw — 創(chuàng)建行為受限的特殊Observable
  • From — 將其它的對象或數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為Observable
  • Interval — 創(chuàng)建一個定時(shí)發(fā)射整數(shù)序列的Observable
  • Just — 將對象或者對象集合轉(zhuǎn)換為一個會發(fā)射這些對象的Observable
  • Range — 創(chuàng)建發(fā)射指定范圍的整數(shù)序列的Observable
  • Repeat — 創(chuàng)建重復(fù)發(fā)射特定的數(shù)據(jù)或數(shù)據(jù)序列的Observable
  • Start — 創(chuàng)建發(fā)射一個函數(shù)的返回值的Observable
  • Timer — 創(chuàng)建在一個指定的延遲之后發(fā)射單個數(shù)據(jù)的Observable

變換操作

  • Buffer — 緩存,可以簡單的理解為緩存,它定期從Observable收集數(shù)據(jù)到一個集合,然后把這些數(shù)據(jù)集合打包發(fā)射,而不是一次發(fā)射一個
  • FlatMap — 扁平映射,將Observable發(fā)射的數(shù)據(jù)變換為Observables集合,然后將這些Observable發(fā)射的數(shù)據(jù)平坦化的放進(jìn)一個單獨(dú)的Observable,可以認(rèn)為是一個將嵌套的數(shù)據(jù)結(jié)構(gòu)展開的過程。
  • GroupBy — 分組,將原來的Observable分拆為Observable集合,將原始Observable發(fā)射的數(shù)據(jù)按Key分組,每一個Observable發(fā)射一組不同的數(shù)據(jù)
  • Map — 映射,通過對序列的每一項(xiàng)都應(yīng)用一個函數(shù)變換Observable發(fā)射的數(shù)據(jù),實(shí)質(zhì)是對序列中的每一項(xiàng)執(zhí)行一個函數(shù),函數(shù)的參數(shù)就是這個數(shù)據(jù)項(xiàng)
  • Scan — 掃描,對Observable發(fā)射的每一項(xiàng)數(shù)據(jù)應(yīng)用一個函數(shù),然后按順序依次發(fā)射這些值
  • Window — 窗口,定期將來自O(shè)bservable的數(shù)據(jù)分拆成一些Observable窗口,然后發(fā)射這些窗口,而不是每次發(fā)射一項(xiàng)。類似于Buffer,但Buffer發(fā)射的是數(shù)據(jù),Window發(fā)射的是Observable,每一個Observable發(fā)射原始Observable的數(shù)據(jù)的一個子集

過濾操作

  • Debounce — 只有在空閑了一段時(shí)間后才發(fā)射數(shù)據(jù),通俗的說,就是如果一段時(shí)間沒有操作,就執(zhí)行一次操作
  • Distinct — 去重,過濾掉重復(fù)數(shù)據(jù)項(xiàng)
  • ElementAt — 取值,取特定位置的數(shù)據(jù)項(xiàng)
  • Filter — 過濾,過濾掉沒有通過謂詞測試的數(shù)據(jù)項(xiàng),只發(fā)射通過測試的
  • First — 首項(xiàng),只發(fā)射滿足條件的第一條數(shù)據(jù)
  • IgnoreElements — 忽略所有的數(shù)據(jù),只保留終止通知(onError或onCompleted)
  • Last — 末項(xiàng),只發(fā)射最后一條數(shù)據(jù)
  • Sample — 取樣,定期發(fā)射最新的數(shù)據(jù),等于是數(shù)據(jù)抽樣,有的實(shí)現(xiàn)里叫ThrottleFirst
  • Skip — 跳過前面的若干項(xiàng)數(shù)據(jù)
  • SkipLast — 跳過后面的若干項(xiàng)數(shù)據(jù)
  • Take — 只保留前面的若干項(xiàng)數(shù)據(jù)
  • TakeLast — 只保留后面的若干項(xiàng)數(shù)據(jù)

組合操作

  • And/Then/When — 通過模式(And條件)和計(jì)劃(Then次序)組合兩個或多個Observable發(fā)射的數(shù)據(jù)集
  • CombineLatest — 當(dāng)兩個Observables中的任何一個發(fā)射了一個數(shù)據(jù)時(shí),通過一個指定的函數(shù)組合每個Observable發(fā)射的最新數(shù)據(jù)(一共兩個數(shù)據(jù)),然后發(fā)射這個函數(shù)的結(jié)果
  • Join — 無論何時(shí),如果一個Observable發(fā)射了一個數(shù)據(jù)項(xiàng),只要在另一個Observable發(fā)射的數(shù)據(jù)項(xiàng)定義的時(shí)間窗口內(nèi),就將兩個Observable發(fā)射的數(shù)據(jù)合并發(fā)射
  • Merge — 將兩個Observable發(fā)射的數(shù)據(jù)組合并成一個
  • StartWith — 在發(fā)射原來的Observable的數(shù)據(jù)序列之前,先發(fā)射一個指定的數(shù)據(jù)序列或數(shù)據(jù)項(xiàng)
  • Switch — 將一個發(fā)射Observable序列的Observable轉(zhuǎn)換為這樣一個Observable:它逐個發(fā)射那些Observable最近發(fā)射的數(shù)據(jù)
  • Zip — 打包,使用一個指定的函數(shù)將多個Observable發(fā)射的數(shù)據(jù)組合在一起,然后將這個函數(shù)的結(jié)果作為單項(xiàng)數(shù)據(jù)發(fā)射

錯誤處理

這些操作符用于從錯誤通知中恢復(fù):

  • Catch — 捕獲,繼續(xù)序列操作,將錯誤替換為正常的數(shù)據(jù),從onError通知中恢復(fù)
  • Retry — 重試,如果Observable發(fā)射了一個錯誤通知,重新訂閱它,期待它正常終止

輔助操作

  • Delay — 延遲一段時(shí)間發(fā)射結(jié)果數(shù)據(jù)
  • Do — 注冊一個動作占用一些Observable的生命周期事件,相當(dāng)于Mock某個操作
  • Materialize/Dematerialize — 將發(fā)射的數(shù)據(jù)和通知都當(dāng)做數(shù)據(jù)發(fā)射,或者反過來
  • ObserveOn — 指定觀察者觀察Observable的調(diào)度程序(工作線程)
  • Serialize — 強(qiáng)制Observable按次序發(fā)射數(shù)據(jù)并且功能是有效的
  • Subscribe — 收到Observable發(fā)射的數(shù)據(jù)和通知后執(zhí)行的操作
  • SubscribeOn — 指定Observable應(yīng)該在哪個調(diào)度程序上執(zhí)行
  • TimeInterval — 將一個Observable轉(zhuǎn)換為發(fā)射兩個數(shù)據(jù)之間所耗費(fèi)時(shí)間的Observable
  • Timeout — 添加超時(shí)機(jī)制,如果過了指定的一段時(shí)間沒有發(fā)射數(shù)據(jù),就發(fā)射一個錯誤通知
  • Timestamp — 給Observable發(fā)射的每個數(shù)據(jù)項(xiàng)添加一個時(shí)間戳
  • Using — 創(chuàng)建一個只在Observable的生命周期內(nèi)存在的一次性資源

條件和布爾操作

這些操作符可用于單個或多個數(shù)據(jù)項(xiàng),也可用于Observable。

  • All — 判斷Observable發(fā)射的所有的數(shù)據(jù)項(xiàng)是否都滿足某個條件
  • Amb — 給定多個Observable,只讓第一個發(fā)射數(shù)據(jù)的Observable發(fā)射全部數(shù)據(jù)
  • Contains — 判斷Observable是否會發(fā)射一個指定的數(shù)據(jù)項(xiàng)
  • DefaultIfEmpty — 發(fā)射來自原始Observable的數(shù)據(jù),如果原始Observable沒有發(fā)射數(shù)據(jù),就發(fā)射一個默認(rèn)數(shù)據(jù)
  • SequenceEqual — 判斷兩個Observable是否按相同的數(shù)據(jù)序列
  • SkipUntil — 丟棄原始Observable發(fā)射的數(shù)據(jù),直到第二個Observable發(fā)射了一個數(shù)據(jù),然后發(fā)射原始Observable的剩余數(shù)據(jù)
  • SkipWhile — 丟棄原始Observable發(fā)射的數(shù)據(jù),直到一個特定的條件為假,然后發(fā)射原始Observable剩余的數(shù)據(jù)
  • TakeUntil — 發(fā)射來自原始Observable的數(shù)據(jù),直到第二個Observable發(fā)射了一個數(shù)據(jù)或一個通知
  • TakeWhile — 發(fā)射原始Observable的數(shù)據(jù),直到一個特定的條件為真,然后跳過剩余的數(shù)據(jù)

算術(shù)和聚合操作

這些操作符可用于整個數(shù)據(jù)序列

  • Average — 計(jì)算Observable發(fā)射的數(shù)據(jù)序列的平均值,然后發(fā)射這個結(jié)果
  • Concat — 不交錯的連接多個Observable的數(shù)據(jù)
  • Count — 計(jì)算Observable發(fā)射的數(shù)據(jù)個數(shù),然后發(fā)射這個結(jié)果
  • Max — 計(jì)算并發(fā)射數(shù)據(jù)序列的最大值
  • Min — 計(jì)算并發(fā)射數(shù)據(jù)序列的最小值
  • Reduce — 按順序?qū)?shù)據(jù)序列的每一個應(yīng)用某個函數(shù),然后返回這個值
  • Sum — 計(jì)算并發(fā)射數(shù)據(jù)序列的和

連接操作

一些有精確可控的訂閱行為的特殊Observable

  • Connect — 指示一個可連接的Observable開始發(fā)射數(shù)據(jù)給訂閱者
  • Publish — 將一個普通的Observable轉(zhuǎn)換為可連接的
  • RefCount — 使一個可連接的Observable表現(xiàn)得像一個普通的Observable
  • Replay — 確保所有的觀察者收到同樣的數(shù)據(jù)序列,即使他們在Observable開始發(fā)射數(shù)據(jù)之后才訂閱

轉(zhuǎn)換操作

  • To — 將Observable轉(zhuǎn)換為其它的對象或數(shù)據(jù)結(jié)構(gòu)
  • Blocking - 阻塞Observable的操作符

使用場景

  • 與 Retrofit 的結(jié)合
  • RxBinding
  • 各種異步操作
  • RxBus

其他

subscribe()不完整定義的回調(diào),Action、Function接口

doOnSubscribe()

Subscriber 的 onStart() 可以用作流程開始前的初始化。然而 onStart() 由于在 subscribe() 發(fā)生時(shí)就被調(diào)用了,因此不能指定線程,而是只能執(zhí)行在 subscribe() 被調(diào)用時(shí)的線程。這就導(dǎo)致如果 onStart() 中含有對線程有要求的代碼(例如在界面上顯示一個 ProgressBar,這必須在主線程執(zhí)行),將會有線程非法的風(fēng)險(xiǎn),因?yàn)橛袝r(shí)你無法預(yù)測 subscribe() 將會在什么線程執(zhí)行。

而與 Subscriber.onStart() 相對應(yīng)的,有一個方法 Observable.doOnSubscribe() 。它和 Subscriber.onStart() 同樣是在 subscribe() 調(diào)用后而且在事件發(fā)送前執(zhí)行,但區(qū)別在于它可以指定線程。默認(rèn)情況下, doOnSubscribe() 執(zhí)行在 subscribe() 發(fā)生的線程;而如果在 doOnSubscribe() 之后有 subscribeOn() 的話,它將執(zhí)行在離它最近的 subscribeOn() 所指定的線程。

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

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