玩轉RxJava2.x 學習教程(一)

依然範特稀西發表於2017-06-25

從16年11月份推出RxJava 2.0 ,到現在差不多大半年的時間裡,RxJava已經來到了2.x時代,RxJava 1.x 可能也慢慢地被2.x 代替。RxJava 2.x在Reactive-Streams規範的基礎上從頭開始完全重寫,雖然操作符基本沒有發生變化,但是因為Reactive-Streams具有不同的架構,因此對一些眾所周知的RxJava型別進行了更改。

RxJava 2.x相對與1.x還是有很多的不同,RxJava的型別更改了,很多類的命名和方法的命名發生了變化(可能功能與1.x相同),要想從RxJava 1.x 順利地過渡到2.x, 就得了解這些變化。因此本教程就帶你瞭解這些變化,從而能更快地上手RxJava2.x。

本篇文章就來先了解一下RxJava 2.x的5種響應型別。

一、RxJava 2.x中5種型別介紹

1 . Observable and Flowable

關於在RxJava 0.x版本引入背壓的一個小的遺憾是,沒有設計一個單獨的基礎反應類,而是對Observable本身進行了改裝。背壓的主要問題在於熱源(如:UI事件),不能合理地反壓並導致不可預料的異常MissingBackpressureException,這是初學者不期望看到的。

在RxJava 2.x版本中修復了這種情況,將o.reactivex.Observable作為非背壓,引入新的io.reactivex.Flowable作為啟用背壓基礎反應類。

好訊息是,在2.x版本中,主要的操作符保持不變(同1.x版本),壞訊息是,在匯入的時候應當小心,它可能會無意的選擇非背壓的o.reactivex.Observable.

我們應該選哪種?

當構建資料流(作為RxJava的最終消費者)或考慮您的2.x相容庫應該採取和返回什麼型別時,您可以考慮幾個因素,以幫助您避免諸如MissingBackpressureException或OutOfMemoryError之類的問題。

Observable使用場景:

  • 資料流最長不超過1000個元素,即隨著時間的流逝,應用沒有機會報OOME(OutOfMemoryError)錯誤。
  • 處理諸如滑鼠移動或觸控事件之類的GUI事件

Flowable使用場景:

  • 處理超過10K+ 的元素流
  • 從磁碟讀取(解析檔案)
  • 從資料庫讀取資料
  • 從網路獲取資料流
2 . Single 使用介紹

Single是2.x版本中的一種基礎響應型別,Single是從頭開始重新設計的,能單獨發射一個onSuccess或者onError事件,它現在的架構來自於the Reactive-Streams設計。它的消費者型別已經從接受rx.Subscriptionrx.Single.SingleSubscriber<T>變為了io.reactivex.SingleObserver<T>,有3個方法:

interface SingleObserver<T> {
    void onSubscribe(Disposable d);
    void onSuccess(T value);
    void onError(Throwable error);
}複製程式碼
3 . Completable使用介紹

Completeble型別基本保持不變,1.x的版本已經沿著Reactive-Streams風格設計,所以沒有使用者級別的更改。

相似地命名改變,rx.Completable.CompletableSubscriber變為帶有onSubscribe(Disposable)方法的io.reactivex.CompletableObserver:

interface CompletableObserver<T> {
    void onSubscribe(Disposable d);
    void onComplete();
    void onError(Throwable error);
}複製程式碼
4 . Maybe 使用介紹

RxJava 2.0.0-RC2 介紹了一個新的基礎響應型別,它叫做Maybe。從概念上來將,它像是 Single和Completable的結合,它可能發射0個或者1個專案,或者一個error訊號。

Maybe類通過依賴MaybeSource作為它的基礎介面型別MaybeObserver<T>作為訊號響應介面並且遵循協議onSubscribe (onSuccess | onError | onComplete)?因為最多可能發射1個元素,所以Maybe型別沒有背壓的概念(因為它沒有像Flowable和Observable一樣有未知長度的可膨脹緩衝區)

這意味著onSubscribe(Disposable)的呼叫潛在地跟隨著其他onXXX方法之一的呼叫,不同於Flowable,如果這兒只有一個訊號值發射訊號,那麼只有onSuccess被呼叫,而不會呼叫complete

二、RxJava 2.x中5種型別使用示例

1 . Observable示例

在寫示例之前,我們先來回顧一下 1.x 版本是如何建立Observable和如何訂閱的:
RxJava 1.x :

  //建立 observable
       Observable observable =  Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                subscriber.onNext("hello world");
                subscriber.onCompleted();
            }
        }).subscribeOn(Schedulers.io())
          .observeOn(AndroidSchedulers.mainThread());

       //訂閱方式一
        observable.subscribe(new Subscriber() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Object o) {

            }
        });

        // 訂閱方式二
         observable.subscribe(new Action1() {
             @Override
             public void call(Object o) {
                 // onNext
             }
         });複製程式碼

通過create方法建立Observable,接收一個OnSubscribe介面,其中有一個回撥方法call,引數為Subscriber,我們用Subscriber來發射資料。通過subscribe方法來訂閱,可以接收一個Subscriber 實現全部方法,也可以接收一個Action1只實現onNext方法。

RxJava 2.x :

       //建立Observable
        Observable observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                Log.e(TAG,"start emitter data");
                e.onNext("Hello");
                e.onNext("world");
                e.onComplete();
            }
        })
          .subscribeOn(Schedulers.io())
          .observeOn(AndroidSchedulers.mainThread());

          // 訂閱方式一:下游消費者 Observer
          observable.subscribe(new Observer<String>() {
              @Override
             public void onSubscribe(@NonNull Disposable d) {
            // onSubscribe 是2.x新新增的方法,在發射資料前被呼叫,相當於1.x的onStart方法
                 Log.e(TAG,"onSubscribe");
              }

              @Override
              public void onNext(@NonNull String s) {
                  Log.e(TAG,"onNext");
                  Log.e(TAG,s);
              }

              @Override
              public void onError(@NonNull Throwable e) {
                  Log.e(TAG,"onError");
              }

              @Override
              public void onComplete() {
                  Log.e(TAG,"onComplete");
              }
          });

         // 訂閱方式二:Consumer
         observable.subscribe(new Consumer<String>() {
             @Override
             public void accept(@NonNull String o) throws Exception {
                  Log.e(TAG,"consumer:"+o);
             }
         });複製程式碼

列印結果如下:

06-25 14:31:35.435 21505-21505/com.zhouwei.demoforrxjava2 E/MainActivity: onSubscribe
06-25 14:31:35.437 21505-21853/com.zhouwei.demoforrxjava2 E/MainActivity: start emitter data
06-25 14:31:35.438 21505-21505/com.zhouwei.demoforrxjava2 E/MainActivity: onNext:Hello
06-25 14:31:35.438 21505-21505/com.zhouwei.demoforrxjava2 E/MainActivity: onNext:world
06-25 14:31:35.438 21505-21505/com.zhouwei.demoforrxjava2 E/MainActivity: onComplete複製程式碼

其實我們可以對比一下,1.x 和 2.x 方法都試一樣的,只是它們所接收的響應介面改變了,對應變化如下:

 RxJava 1.x       ->   RxJava 2.x
 ---------------------------------------
 OnSubscribe   ->   ObservableOnSubscribe
 Subscriber    ->   Observer
 Subscriber    ->   ObservableEmitter
 Action1       ->   Consumer複製程式碼

RxJava 2.x 中對這些介面進行了重新設計,讓一個介面的職責更加單一,類的命名和方法命名與它的功能更佳符合(見名知意)。如在1.x 中,Subscriber 既能發射資料,又能消費資料,充當觀察者和被觀察者。在2.x 中 把它拆解成了2個介面。ObservableEmitter<T>專門用來發射資料,Consumer 專門用來消費資料。 除此之外,在RxJava 2.x 中,多了一個void onSubscribe(@NonNull Disposable d)回撥方法,引數為Disposable,Disposable是用來解除訂閱關係的,這讓我們的解除訂閱變得更佳容易(比起1.x 通過subscribe返回 Subscription)。

上面對比了在RxJava 1.x 和2.x 版本建立Observable的方式,其實在RxJava 2.x中,這5種型別的用法是非常相似的,它們的介面命名規則相同,只要你知道其中一種,就知道其他幾種型別該如何在上游發射資料和在下游消費資料。create接收的型別都為xxxOnSubscrible(xxx為5種型別對應的名字),發射器為xxxEmitter,具體如下表:

RxJava 2.x 型別 create引數(響應介面) 發射器 Observer
Observable ObservableOnSubscribe ObservableEmitter Observer
Flowable FlowableOnSubscribe FlowableEmitter FlowableSubscriber
Single SingleOnSubscribe SingleEmitter SingleObserver
Completable CompletableOnSubscribe CompletableEmitter CompletableObserver
Maybe MaybeOnSubscribe MaybeEmitter MaybeObserver
2 . Flowable示例

上面對比了RxJava 1.x 和 2.x 建立使用Observable的方式,並且總結了2.x 相關類的改變,如上面表。那麼使用Flowable的方式和Observable是很相似的,看一下程式碼:

Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull FlowableEmitter<Integer> e) throws Exception {
                Log.e(TAG,"start send data ");
                for(int i=0;i<100;i++){
                    e.onNext(i);
                }
                e.onComplete();
            }
        }, BackpressureStrategy.DROP)//指定背壓策略
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new FlowableSubscriber<Integer>() {
            @Override
            public void onSubscribe(@NonNull Subscription s) {
               //1, onSubscribe 是2.x新新增的方法,在發射資料前被呼叫,相當於1.x的onStart方法
               //2, 引數為  Subscription ,Subscription 可用於向上遊請求發射多少個元素,也可用於取笑請求
               //3,  必須要呼叫Subscription 的request來請求發射資料,不然上游是不會發射資料的。
               Log.e(TAG,"onSubscribe...");
               subscription = s;
                s.request(100);
            }

            @Override
            public void onNext(Integer integer) {
                Log.e(TAG,"onNext:"+integer);
            }

            @Override
            public void onError(Throwable t) {
                Log.e(TAG,"onError..."+t);
            }

            @Override
            public void onComplete() {
                Log.e(TAG,"onComplete...");
            }
        });複製程式碼

Flowable和Observable的使用基本相同,只不過Observable不支援背壓,而Flowable支援背壓。使用的時候,還是要注意幾個小細節:
1,建立Flowable的時候需要指定一個背壓策略,本文使用的是PBackpressureStrategy.DROP(丟棄策略),RxJava 2.x中,內建了5種背壓策略,由於篇幅有限,背壓和背壓策略下一篇拿出來單獨講。
2,onSubscribe 回撥方法中,引數是Subscription而不是Disposable,前文說過,RxJava 2.x 中,訂閱的管理換成了Disposable,但是Flowable使用的是Subscription,這個Subscription不是1.x 版本中的Subscription,雖然它有取消訂閱的能力。主要用於請求上游元素和取消訂閱。
3,在使用Flowable的時候,必須呼叫Subscription 的requsest方法請求,不然上游是不會發射資料的。看request的方法解釋:

3 . Single、Completable 和 Maybe 示例

Single、Completable和Maybe就比較簡單,Single用於只發射一個資料,Completable不傳送資料,它給下游發射一個訊號。而Maybe則是Single和Completable的結合,根據名字就可以看出,它的結果是不確定的,可能發發射0(Completable)或1(Single) 個元素,或者收到一個Error訊號。

Single示例:

Single.create(new SingleOnSubscribe<Boolean>() {
            @Override
            public void subscribe(@NonNull SingleEmitter<Boolean> e) throws Exception {
                Log.e(TAG,"subscribe...");
                e.onSuccess(true);
            }
        })
        .observeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new SingleObserver<Boolean>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                Log.e(TAG,"onSubscribe...");
            }

            @Override
            public void onSuccess(@NonNull Boolean aBoolean) {
                Log.e(TAG,"onSuccess...");
            }

            @Override
            public void onError(@NonNull Throwable e) {
                Log.e(TAG,"onError...");
            }
        });複製程式碼

Single只發射一個元素,所以沒有complete 方法,不像Observable或者Flowable,資料發射完成之後,需要呼叫complete告訴下游已經完成。

Completable示例:

 Completable.create(new CompletableOnSubscribe() {
            @Override
            public void subscribe(@NonNull CompletableEmitter e) throws Exception {
               Log.e(TAG,"start send data");
               e.onComplete();
            }
        }).subscribeOn(Schedulers.io())
          .observeOn(AndroidSchedulers.mainThread())
          .subscribe(new CompletableObserver() {
              @Override
              public void onSubscribe(@NonNull Disposable d) {
                  Log.e(TAG,"onSubscribe");
              }

              @Override
              public void onComplete() {
                Log.e(TAG,"onComplete");
              }

              @Override
              public void onError(@NonNull Throwable e) {
                  Log.e(TAG,"onError");
              }
          });複製程式碼

Completable 不會發射資料,只會給下游傳送一個訊號。回撥 onComplete方法。

Maybe示例:

 Maybe.create(new MaybeOnSubscribe<Boolean>() {
            @Override
            public void subscribe(@NonNull MaybeEmitter<Boolean> e) throws Exception {
                Log.e(TAG,"start send data");
                 e.onSuccess(true);
                 e.onComplete();

            }
        }).subscribeOn(Schedulers.io())

           .observeOn(AndroidSchedulers.mainThread())

           .subscribe(new MaybeObserver<Boolean>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                Log.e(TAG,"onSubscribe");
            }

            @Override
            public void onSuccess(@NonNull Boolean aBoolean) {
                Log.e(TAG,"1->onSuccess:"+aBoolean);
            }

            @Override
            public void onError(@NonNull Throwable e) {
                Log.e(TAG,"onError");
            }

            @Override
            public void onComplete() {
                Log.e(TAG,"onComplete");
            }
        });複製程式碼

Maybe是Single和Completable的結合,需要注意的是onSuccessonComplete方法只會執行其中一個,這不同於Observable和Flowable最後是以onComplete()結尾.

如上面的程式碼,先呼叫onSuccess發射一個元素,再呼叫onComplete

e.onComplete();
e.onSuccess(true);複製程式碼

最後列印結果如下:

E/MainActivity: onSubscribe
E/MainActivity: start send data
E/MainActivity: onComplete複製程式碼

可以看到只回撥了 onComplete,我們把呼叫的順序調換一下:

e.onSuccess(true);
e.onComplete();複製程式碼

列印結果如下:

E/MainActivity: onSubscribe
E/MainActivity: start send data
E/MainActivity: 1->onSuccess:true複製程式碼

可以看到調換了之後列印OnSucces()而沒有列印onComplete(),這也印證了只會回撥其中之一。

三、總結

RxJava 2.x 相比於 1.x 還是有很大的變化,雖然操作符基本不變,但是很多類和介面都是基於Reactive-Streams 規範重新設計的,命名也發生了變換,要想玩轉RxJava 2.x ,你得了解這些變化和使用場景,本文介紹了RxJava 2.x 的5種基礎響應型別,希望對才開始學習RxJava 2.x 的同學有所幫助。

參考:
What's different in 2.0

如果你喜歡我的文章,歡迎關注我的微信公眾號:Android技術雜貨鋪,第一時間獲取有價值的Android乾貨文章。
微信公眾號:Android技術雜貨鋪

相關文章