Android Rxjava :最簡單&全面背壓講解 (Flowable)

Android心路歷程發表於2019-04-20

1.前言

閱讀本文需要對Rxjava瞭解,如果還沒有了解或者使用過Rxjava的兄die們,可以觀看我另外一篇 Android Rxjava:不一樣的詮釋進行學習。

Rxjava背壓被觀察者傳送事件的速度大於觀察者接收事件的速度時,觀察者內會建立一個無限制大少的緩衝池儲存未接收的事件,因此當儲存的事件越來越多時就會導致OOM的出現。(注:當subscribeOn與observeOn不為同一個執行緒時,被觀察者與觀察者記憶體在不同時長耗時任務,就會使傳送與接收速度存在差異。)

背壓例子

public void backpressureSample(){
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                int i = 0;
                while(true){
                    Thread.sleep(500);
                    i++;
                    e.onNext(i);
                    Log.i(TAG,"每500ms傳送一次資料:"+i);
                }
            }
        }).subscribeOn(Schedulers.newThread())//使被觀察者存在獨立的執行緒執行
          .observeOn(Schedulers.newThread())//使觀察者存在獨立的執行緒執行
          .subscribe(new Consumer<Integer>() {
              @Override
              public void accept(Integer integer) throws Exception {
                  Thread.sleep(5000);
                  Log.e(TAG,"每5000m接收一次資料:"+integer);
              }
          });
    }
複製程式碼

例子執行效果

Android Rxjava :最簡單&全面背壓講解 (Flowable)
Android Rxjava :最簡單&全面背壓講解 (Flowable)

通過上述例子可以大概瞭解背壓是如何產生,因此Rxjava2.0版本提供了 Flowable 解決背壓問題。
本文章就是使用與分析 Flowable 是如何解決背壓問題。
文章中例項 linhaojian的Github

2.目錄

Android Rxjava :最簡單&全面背壓講解 (Flowable)

3.簡介

Android Rxjava :最簡單&全面背壓講解 (Flowable)

4.使用與原理詳解

4.1 Flowable 與 Observable 的區別

Android Rxjava :最簡單&全面背壓講解 (Flowable)
flowable與observable對比

上圖可以很清楚看出二者的區別,其實Flowable 出來以上的區別之外,它其他所有使用與Observable完全一樣。

Flowable 的create例子

 public void flowable(){
        Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> e) throws Exception {
                for(int j = 0;j<=150;j++){
                    e.onNext(j);
                    Log.i(TAG," 傳送資料:"+j);
                    try{
                        Thread.sleep(50);
                    }catch (Exception ex){
                    }
                }
            }
        },BackpressureStrategy.ERROR)
        .subscribeOn(Schedulers.newThread())
        .observeOn(Schedulers.newThread())
        .subscribe(new Subscriber<Integer>() {
            @Override
            public void onSubscribe(Subscription s) {
                s.request(Long.MAX_VALUE); //觀察者設定接收事件的數量,如果不設定接收不到事件
            }
            @Override
            public void onNext(Integer integer) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.e(TAG,"onNext : "+(integer));
            }
            @Override
            public void onError(Throwable t) {
                Log.e(TAG,"onError : "+t.toString());
            }
            @Override
            public void onComplete() {
                Log.e(TAG,"onComplete");
            }
        });
    }
複製程式碼

4.2 BackpressureStrategy媒體類

從Flowable原始碼檢視,快取池預設大少為:128

public abstract class Flowable<T> implements Publisher<T> {
    /** The default buffer size. */
    static final int BUFFER_SIZE;
    static {
        BUFFER_SIZE = Math.max(1, Integer.getInteger("rx2.buffer-size", 128));
    }
    .....
}
複製程式碼

通過上面的例子,我們可以看到create方法中的包含了一個BackpressureStrategy媒體類,其包含5種型別:

4.2.1. ERROR

把上面例子改為ERROR型別,執行結果如下:

Android Rxjava :最簡單&全面背壓講解 (Flowable)

總結 :當被觀察者傳送事件大於128時,觀察者丟擲異常並終止接收事件,但不會影響被觀察者繼續傳送事件。

4.2.2. BUFFER

把上面例子改為BUFFER型別,執行結果如下:

Android Rxjava :最簡單&全面背壓講解 (Flowable)

總結 :與Observable一樣存在背壓問題,但是接收效能比Observable低,因為BUFFER型別通過BufferAsyncEmitter新增了額外的邏輯處理,再傳送至觀察者。

4.2.3. DROP

把上面例子改為DROP型別,執行結果如下:

Android Rxjava :最簡單&全面背壓講解 (Flowable)

總結 :每當觀察者接收128事件之後,就會丟棄部分事件

4.2.4. LATEST

把上面例子改為LATEST型別,執行結果如下:

Android Rxjava :最簡單&全面背壓講解 (Flowable)

總結 :LATEST與DROP使用效果一樣,但LATEST會保證能接收最後一個事件,而DROP則不會保證。

4.2.5. MISSING

把上面例子改為MISSING型別,執行結果如下:

Android Rxjava :最簡單&全面背壓講解 (Flowable)

總結 :MISSING就是沒有采取背壓策略的型別,效果跟Obserable一樣。

在設定MISSING型別時,可以配合onBackPressure相關操作符使用,也可以到達上述其他型別的處理效果。

4.3 onBackPressure相關操作符

使用例子:

 Flowable.interval(50,TimeUnit.MILLISECONDS)
        .onBackpressureDrop()//效果與Drop型別一樣
        .subscribeOn(Schedulers.newThread())
        .observeOn(Schedulers.newThread())
        .subscribe(new Consumer<Long>() {
            @Override
            public void accept(Long aLong) throws Exception {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.e(TAG,"onNext : "+(aLong));
            }
        });
複製程式碼

onBackpressureBuffer :與BUFFER型別一樣效果。
onBackpressureDrop :與DROP型別一樣效果。
onBackpressureLaster :與LASTER型別一樣效果。

4.4 request()

4.4.1 request(int count):設定接收事件的數量.

例子:

Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> e) throws Exception {
                for(int j = 0;j<50;j++){
                    e.onNext(j);
                    Log.i(TAG," 傳送資料:"+j);
                    try{
                        Thread.sleep(50);
                    }catch (Exception ex){
                    }
                }
            }
        },BackpressureStrategy.BUFFER)
        .subscribeOn(Schedulers.newThread())
        .observeOn(Schedulers.newThread())
        .subscribe(new Subscriber<Integer>() {
            @Override
            public void onSubscribe(Subscription s) {
                s.request(10); //觀察者設定接收事件的數量,如果不設定接收不到事件
            }
            @Override
            public void onNext(Integer integer) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.e(TAG,"onNext : "+(integer));
            }
            @Override
            public void onError(Throwable t) {
                Log.e(TAG,"onError : "+t.toString());
            }
            @Override
            public void onComplete() {
                Log.e(TAG,"onComplete");
            }
        });
複製程式碼
Android Rxjava :最簡單&全面背壓講解 (Flowable)

4.4.2 request擴充套件使用

request還可進行擴充套件使用,當遇到在接收事件時想追加接收數量(如:通訊資料通過幾次接收,驗證準確性的應用場景),可以通過以下方式進行擴充套件:

Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> e) throws Exception {
                for(int j = 0;j<50;j++){
                    e.onNext(j);
                    Log.i(TAG," 傳送資料:"+j);
                    try{
                        Thread.sleep(50);
                    }catch (Exception ex){
                    }
                }
            }
        },BackpressureStrategy.BUFFER)
        .subscribeOn(Schedulers.newThread())
        .observeOn(Schedulers.newThread())
        .subscribe(new Subscriber<Integer>() {
            private Subscription subscription;
            @Override
            public void onSubscribe(Subscription s) {
                subscription = s;
                s.request(10); //觀察者設定接收事件的數量,如果不設定接收不到事件
            }
            @Override
            public void onNext(Integer integer) {
                if(integer==5){
                    subscription.request(3);
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.e(TAG,"onNext : "+(integer));
            }
            @Override
            public void onError(Throwable t) {
                Log.e(TAG,"onError : "+t.toString());
            }
            @Override
            public void onComplete() {
                Log.e(TAG,"onComplete");
            }
        });
複製程式碼
Android Rxjava :最簡單&全面背壓講解 (Flowable)

總結:可以動態設定觀察者接收事件的數量,但不影響被觀察者繼續傳送事件。

4.5 requested

requestedrequest不是同一的函式,但它們都是屬於FlowableEmitter類裡的方法,那麼requested()是有什麼作用呢,看看以下例子:

Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> e) throws Exception {
                for(int j = 0;j<15;j++){
                    e.onNext(j);
                    Log.i(TAG,e.requested()+" 傳送資料:"+j);
                    try{
                        Thread.sleep(50);
                    }catch (Exception ex){
                    }
                }
            }
        },BackpressureStrategy.BUFFER)
//        .subscribeOn(Schedulers.newThread())
//        .observeOn(Schedulers.newThread())
        .subscribe(new Subscriber<Integer>() {
            private Subscription subscription;
            @Override
            public void onSubscribe(Subscription s) {
                subscription = s;
                s.request(10); //觀察者設定接收事件的數量,如果不設定接收不到事件
            }
            @Override
            public void onNext(Integer integer) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.e(TAG,"onNext : "+(integer));
            }
            @Override
            public void onError(Throwable t) {
                Log.e(TAG,"onError : "+t.toString());
            }
            @Override
            public void onComplete() {
                Log.e(TAG,"onComplete");
            }
        });
複製程式碼
Android Rxjava :最簡單&全面背壓講解 (Flowable)

從圖中我們可以發現,requested列印的結果就是 剩餘可接收的數量 ,它的作用就是可以檢測剩餘可接收的事件數量。

5.總結

到此,Flowable講解完畢。
如果喜歡我的分享,可以點選 關注 或者 喜歡,你們支援是我分享的最大動力 。


相關文章