RxJava學習篇之一:基礎Observable,Observer,Single,Subject,Scheduler

一、Observable,Observer

在ReactiveX中,一個觀察者(Observer)訂閱一個可觀察對象(Observable)。觀察者對Observable發射的數據或數據序列作出響應。這種模式可以極大地簡化併發操作,因爲它創建了一個處於待命狀態的觀察者哨兵,在未來某個時刻響應Observable的通知,不需要阻塞等待Observable發射數據。

回調方法 (onNext, onCompleted, onError)
Subscribe方法用於將觀察者連接到Observable,你的觀察者需要實現以下方法的一個子集:
onNext(T item)
Observable調用這個方法發射數據,方法的參數就是Observable發射的數據,這個方法可能會被調用多次,取決於你的實現。
onError(Exception ex)
當Observable遇到錯誤或者無法返回期望的數據時會調用這個方法,這個調用會終止Observable,後續不會再調用onNext和onCompleted,onError方法的參數是拋出的異常。
onComplete
正常終止,如果沒有遇到錯誤,Observable在最後一次調用onNext之後調用此方法。根據Observable協議的定義,onNext可能會被調用零次或者很多次,最後會有一次onCompleted或onError調用(不會同時),傳遞數據給onNext通常被稱作發射,onCompleted和onError被稱作通知。

取消訂閱 (Unsubscribing)
在一些ReactiveX實現中,有一個特殊的觀察者接口Subscriber,它有一個unsubscribe方法。調用這個方法表示你不關心當前訂閱的Observable了,因此Observable可以選擇停止發射新的數據項(如果沒有其它觀察者訂閱)。取消訂閱的結果會傳遞給這個Observable的操作符鏈,而且會導致這個鏈條上的每個環節都停止發射數據項。這些並不保證會立即發生,然而,對一個Observable來說,即使沒有觀察者了,它也可以在一個while循環中繼續生成並嘗試發射數據項。

Observables的"熱"和"冷"
Observable什麼時候開始發射數據序列?這取決於Observable的實現,一個"熱"的Observable可能一創建完就開始發射數據,因此所有後續訂閱它的觀察者可能從序列中間的某個位置開始接受數據(有一些數據錯過了)。一個"冷"的Observable會一直等待,直到有觀察者訂閱它纔開始發射數據,因此這個觀察者可以確保會收到整個數據序列。在一些ReactiveX實現裏,還存在一種被稱作Connectable的Observable,不管有沒有觀察者訂閱它,這種Observable都不會開始發射數據,除非Connect方法被調用。

RxJava
在RxJava中,一個實現了Observer接口的對象可以訂閱(subscribe)一個Observable 類的實例。訂閱者(subscriber)對Observable發射(emit)的任何數據或數據序列作出響應。這種模式簡化了併發操作,因爲它不需要阻塞等待bservable發射數據,而是創建了一個處於待命狀態的觀察者哨兵,哨兵在未來某個時刻響應Observable的通知。

好了!上面都已一些理論知識.下面開始詳細的講解:

二、Single

Single類似於Observable,不同的是,它總是隻發射一個值,或者一個錯誤通知,而不是發射一系列的值。
因此,不同於Observable需要三個方法onNext, onError, onCompleted,訂閱Single只需要兩個方法:
onSuccess - Single發射單個的值到這個方法
onError - 如果無法發射需要的值,Single發射一個Throwable對象到這個方法
Single只會調用這兩個方法中的一個,而且只會調用一次,調用了任何一個方法之後,訂閱關係終止。

 private void testSigngleOperator(){
        Single.create(new Single.OnSubscribe<String>() {
            @Override
            public void call(SingleSubscriber<? super String> singleSubscriber) {
                singleSubscriber.onSuccess("success");
            }
        }).subscribe(new SingleSubscriber<String>() {
            @Override
            public void onSuccess(String value) {
                System.out.print("onSuccess:"+value);
            }

            @Override
            public void onError(Throwable error) {
                System.out.print("onError:"+error);
            }
        });
    }
輸出的結果是:

onSuccess:success

Single也是可以使用onNext, onError, onCompleted這個回調的:

  private void testSigngleOperator(){
        Single.create(new Single.OnSubscribe<String>() {
            @Override
            public void call(SingleSubscriber<? super String> singleSubscriber) {
                singleSubscriber.onSuccess("success");
            }
        }).subscribe(new Subscriber<String>() {
            @Override
            public void onCompleted() {
                System.out.println("onCompleted");
            }

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

            @Override
            public void onNext(String s) {
                System.out.println("onNext:"+s);
            }
        });
    }
輸出的結果是:

onNext:success
onCompleted

Single的操作符

Single也可以組合使用多種操作,一些操作符讓你可以混合使用Observable和Single:

操作符 返回值 說明
compose Single 創建一個自定義的操作符
concat and concatWith Observable 連接多個Single和Observable發射的數據
create Single 調用觀察者的create方法創建一個Single
error Single 返回一個立即給訂閱者發射錯誤通知的Single
flatMap Single 返回一個Single,它發射對原Single的數據執行flatMap操作後的結果
flatMapObservable Observable 返回一個Observable,它發射對原Single的數據執行flatMap操作後的結果
from Single 將Future轉換成Single
just Single 返回一個發射一個指定值的Single
map Single 返回一個Single,它發射對原Single的數據執行map操作後的結果
merge Single 將一個Single(它發射的數據是另一個Single,假設爲B)轉換成另一個Single(它發射來自另一個Single(B)的數據)
merge and mergeWith Observable 合併發射來自多個Single的數據
observeOn Single 指示Single在指定的調度程序上調用訂閱者的方法
onErrorReturn Single 將一個發射錯誤通知的Single轉換成一個發射指定數據項的Single
subscribeOn Single 指示Single在指定的調度程序上執行操作
timeout Single 它給原有的Single添加超時控制,如果超時了就發射一個錯誤通知
toSingle Single 將一個發射單個值的Observable轉換爲一個Single
zip and zipWith Single 將多個Single轉換爲一個,後者發射的數據是對前者應用一個函數後的結果

三、Subject

Subject可以看成是一個橋樑或者代理,它同時充當了Observer和Observable的角色。因爲它是一個Observer,它可以訂閱一個或多個Observable;又因爲它是一個Observable,它可以轉發它收到(Observe)的數據,也可以發射
新的數據。由於一個Subject訂閱一個Observable,它可以觸發這個Observable開始發射數據(如果那個Observable是"冷"的--就是說,它等待有訂閱纔開始發射數據)。因此有這樣的效果,Subject可以把原來那個"冷"的Observable變成"熱"的。

針對不同的場景Subject一共有四種類型:AsyncSubject、BehaviorSubject、PublishSubject和ReplaySubject。

1,AsyncSubject

一個AsyncSubject只在原始Observable完成後,發射來自原始Observable的最後一個值。(如果原始Observable沒有發射任何值,AsyncSubject也不發射任何值)它會把這最後一個值發射給任何後續的觀察者。然而,如果原始的Observable因爲發生了錯誤而終止,AsyncSubject將不會發射任何數據,只是簡單的向前傳遞這個錯誤通知。

a,AsyncSubject當做Observer:

 private void testAsyncSubject() {
        AsyncSubject<String> asyncSubject = AsyncSubject.create();

        Observable.just("1", "2", "3")
                .subscribe(asyncSubject);

        asyncSubject.subscribe(new Subscriber<String>() {
            @Override
            public void onCompleted() {
                System.out.println("onCompleted");
            }

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

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

輸出的結果是:
onNext:3
onCompleted

如果Observable因爲錯誤發了終止:

 private void testAsyncSubject() {
        AsyncSubject<String> asyncSubject = AsyncSubject.create();

        Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                subscriber.onNext("1");
                subscriber.onError(new Exception("asyncSubjectError"));
                subscriber.onNext("2");
                subscriber.onNext("3");
                subscriber.onCompleted();
            }
        }).subscribe(asyncSubject);

        asyncSubject.subscribe(new Subscriber<String>() {
            @Override
            public void onCompleted() {
                System.out.println("onCompleted");
            }

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

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

輸出的結果是:

onError:asyncSubjectError

b,AsyncSubject當做Observable

 private void testAsyncSubject(){
            AsyncSubject<String> asyncSubject =AsyncSubject.create();
            asyncSubject.subscribe(new Subscriber<String>() {
                @Override
                public void onCompleted() {
                    System.out.println("onCompleted");
                }

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

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

            asyncSubject.onNext("1");
            asyncSubject.onNext("2");
            asyncSubject.onNext("3");
            asyncSubject.onCompleted();
        }
輸出的結果是:

onNext:3
onCompleted

2,BehaviorSubject

當觀察者訂閱BehaviorSubject時,它開始發射原始Observable最近發射的數據(如果此時還沒有收到任何數據,它會發射一個默認值),然後繼續發射其它任何來自原始Observable的數據。然而,如果原始的Observable因爲發生了一個錯誤而終止,BehaviorSubject將不會發射任何數據,只是簡單的向前傳遞這個錯誤通知。

 private void testBehaviorSubject(){
        BehaviorSubject<String> behaviorSubject = BehaviorSubject.create("default");
        Subscriber subscriber = new Subscriber<String>() {
            @Override
            public void onCompleted() {
                System.out.println("onCompleted");
            }

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

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

        behaviorSubject.onNext("1");
        behaviorSubject.onNext("2");
        behaviorSubject.onNext("3");
        behaviorSubject.subscribe(subscriber);
        behaviorSubject.onNext("4");
        behaviorSubject.onNext("5");
        behaviorSubject.onCompleted();
    }
輸出的結果是:

onNext:3
onNext:4
onNext:5
onCompleted

3,PublishSubject

PublishSubject只會把在訂閱發生的時間點之後來自原始Observable的數據發射給觀察者。需要注意的是,PublishSubject可能會一創建完成就立刻開始發射數據(除非你可以阻止它發生),因此這裏有一個風險:在Subject被創建後到有觀察者訂閱它之前這個時間段內,一個或多個數據可能會丟失。如果要確保來自原始Observable的所有數據都被分發,你需要這樣做:或者使用Create創建那個Observable以便手動給它引入"冷"Observable的行爲(當所有觀察者都已經訂閱時纔開始發射數據),或者改用ReplaySubject。

 private void testPublishSubject(){
        PublishSubject<String> publishSubject = PublishSubject.create();
        Subscriber subscriber = new Subscriber<String>() {
            @Override
            public void onCompleted() {
                System.out.println("onCompleted");
            }

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

            @Override
            public void onNext(String s) {
                System.out.println("onNext:"+s);
            }
        };
        publishSubject.onNext("1");
        publishSubject.onNext("2");
        publishSubject.onNext("3");
        publishSubject.subscribe(subscriber);
        publishSubject.onNext("4");
        publishSubject.onCompleted();
    }
輸出的結果是:

onNext:4
onCompleted

這就是丟失了1,2,3這三個數據。

4,ReplaySubject

ReplaySubject會發射所有來自原始Observable的數據給觀察者,無論它們是何時訂閱的。也有其它版本的ReplaySubject,在重放緩存增長到一定大小的時候或過了一段時間後會丟棄舊的數據(原始Observable發射的)。
如果你把ReplaySubject當作一個觀察者使用,注意不要從多個線程中調用它的onNext方法(包括其它的on系列方法),這可能導致同時(非順序)調用,這會違反Observable協議,給Subject的結果增加了不確定性。

 private void testReplaySubject(){
        ReplaySubject<String> replaySubject = ReplaySubject.create();
        Subscriber subscriber = new Subscriber<String>() {
            @Override
            public void onCompleted() {
                System.out.println("onCompleted");
            }

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

            @Override
            public void onNext(String s) {
                System.out.println("onNext:"+s);
            }
        };
        replaySubject.onNext("1");
        replaySubject.onNext("2");
        replaySubject.onNext("3");
        replaySubject.subscribe(subscriber);
        replaySubject.onNext("4");
        replaySubject.onCompleted();
    }
輸出的結果是:

onNext:1
onNext:2
onNext:3
onNext:4
onCompleted
沒有丟失數據。

再看這個代碼:

 private void testReplaySubject(){
        ReplaySubject<String> replaySubject = ReplaySubject.createWithSize(2);
        Subscriber subscriber = new Subscriber<String>() {
            @Override
            public void onCompleted() {
                System.out.println("onCompleted");
            }

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

            @Override
            public void onNext(String s) {
                System.out.println("onNext:"+s);
            }
        };
        replaySubject.onNext("1");
        replaySubject.onNext("2");
        replaySubject.onNext("3");
        replaySubject.subscribe(subscriber);
        replaySubject.onNext("4");
        replaySubject.onCompleted();
    }
輸出結果是:

onNext:2
onNext:3
onNext:4
onCompleted
丟失了一個數據“1”,因爲我設置了緩存大小爲2。ReplaySubject.createWithSize()用來控制緩存大小,ReplaySubject.createWithTime()用來控制緩存的時間,ReplaySubject.createWithTimeAndSize()用來控制緩存的大小和緩存的時間。

ps:串行化

如果你把  Subject  當作一個  Subscriber  使用,注意不要從多個線程中調用它的onNext方法(包括其它的on系列方法),這可能導致同時(非順序)調用,這會違反Observable協議,給Subject的結果增加了不確定性。要避免此類問題,你可以將  Subject  轉換爲一個  SerializedSubject  ,類似於這樣:

mySafeSubject = new SerializedSubject( myUnsafeSubject );
四、Scheduler

如果你想給Observable操作符鏈添加多線程功能,你可以指定操作符(或者特定的Observable)在特定的調度器(Scheduler)上執行。

某些ReactiveX的Observable操作符有一些變體,它們可以接受一個Scheduler參數。這個參數指定操作符將它們的部分或全部任務放在一個特定的調度器上執行。

使用ObserveOn和SubscribeOn操作符,你可以讓Observable在一個特定的調度器上執行,ObserveOn指示一個Observable在一個特定的調度器上調用觀察者的onNext, onError和onCompleted方法,SubscribeOn更進一步,它指示Observable將全部的處理過程(包括髮射數據和通知)放在特定的調度器上執行。

RxJava示例

調度器的種類

下表展示了RxJava中可用的調度器種類:

調度器類型 效果
Schedulers.computation( ) 用於計算任務,如事件循環或和回調處理,不要用於IO操作(IO操作請使用Schedulers.io());默認線程數等於處理器的數量
Schedulers.from(executor) 使用指定的Executor作爲調度器
Schedulers.immediate( ) 在當前線程立即開始執行任務
Schedulers.io( ) 用於IO密集型任務,如異步阻塞IO操作,這個調度器的線程池會根據需要增長;對於普通的計算任務,請使用Schedulers.computation();Schedulers.io( )默認是一個CachedThreadScheduler,很像一個有線程緩存的新線程調度器
Schedulers.newThread( ) 爲每個任務創建一個新線程
Schedulers.trampoline( ) 當其它排隊的任務完成後,在當前線程排隊開始執行

默認調度器

在RxJava中,某些Observable操作符的變體允許你設置用於操作執行的調度器,其它的則不在任何特定的調度器上執行,或者在一個指定的默認調度器上執行。下面的表格個列出了一些操作符的默認調度器:

操作符 調度器
buffer(timespan) computation
buffer(timespan, count) computation
buffer(timespan, timeshift) computation
debounce(timeout, unit) computation
delay(delay, unit) computation
delaySubscription(delay, unit) computation
interval computation
repeat trampoline
replay(time, unit) computation
replay(buffersize, time, unit) computation
replay(selector, time, unit) computation
replay(selector, buffersize, time, unit) computation
retry trampoline
sample(period, unit) computation
skip(time, unit) computation
skipLast(time, unit) computation
take(time, unit) computation
takeLast(time, unit) computation
takeLast(count, time, unit) computation
takeLastBuffer(time, unit) computation
takeLastBuffer(count, time, unit) computation
throttleFirst computation
throttleLast computation
throttleWithTimeout computation
timeInterval immediate
timeout(timeoutSelector) immediate
timeout(firstTimeoutSelector, timeoutSelector) immediate
timeout(timeoutSelector, other) immediate
timeout(timeout, timeUnit) computation
timeout(firstTimeoutSelector, timeoutSelector, other) immediate
timeout(timeout, timeUnit, other) computation
timer computation
timestamp immediate
window(timespan) computation
window(timespan, count) computation
window(timespan, timeshift) computation

使用調度器

除了將這些調度器傳遞給RxJava的Observable操作符,你也可以用它們調度你自己的任務。下面的示例展示了Scheduler.Worker的用法:

遞歸調度器:

worker = Schedulers.newThread().createWorker();
worker.schedule(new Action0() {
@Override
public void call() {
yourWork();
// recurse until unsubscribed (schedule will do nothing if unsubscribed)
worker.schedule(this);
}
});
// some time later...
worker.unsubscribe();
Worker類的對象實現了Subscription接口,使用它的isUnsubscribed和unsubscribe方法,所以
你可以在訂閱取消時停止任務,或者從正在調度的任務內部取消訂閱。

private void testScheduler(){
        final Scheduler.Worker worker = Schedulers.newThread().createWorker();
        worker.schedule(new Action0() {
            @Override
            public void call() {
                int i = 0;
                while (!worker.isUnsubscribed()){
                    i++;
                    System.out.println(i+"");
                    if (i == 10){
                        worker.unsubscribe();
                    }
                }
            }
        });
    }
輸出的結果是:

1
2
3
4
5
6
7
8
9
10

延時和週期調度器:
你可以使用schedule(action,delayTime,timeUnit)在指定的調度器上延時執行你的任務,下面
例子中的任務將在500毫秒之後開始執行:
someScheduler.schedule(someAction, 500, TimeUnit.MILLISECONDS);
使用另一個版本的schedule,schedulePeriodically(action,initialDelay,period,timeUnit)方法讓
你可以安排一個定期執行的任務,下面例子的任務將在500毫秒之後執行,然後每250毫秒執
行一次:
someScheduler.schedulePeriodically(someAction, 500, 250, TimeUnit.MILLISECONDS);
測試調度器:
TestScheduler讓你可以對調度器的時鐘表現進行手動微調。這對依賴精確時間安排的任務的測試很有用處。這個調度器有三個額外的方法:
a,advanceTimeTo(time,unit) 向前波動調度器的時鐘到一個指定的時間點
b,advanceTimeBy(time,unit) 將調度器的時鐘向前撥動一個指定的時間段
c,triggerActions( ) 開始執行任何計劃中的但是未啓動的任務,如果它們的計劃時間等於或者早於調度器時鐘的當前時間


資料參考:https://mcxiaoke.gitbooks.io/rxdocs/content/

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