關於rxjava(五)

在這一節裏我們先來學習如何使用Flowable, 它東西比較多, 也比較繁瑣, 解釋起來也比較麻煩, 但我還是儘量用通俗易懂的話來說清楚, 畢竟, 這是一個通俗易懂的教程.

正題

我們還是以兩根水管舉例子:


之前我們所的上游和下游分別是ObservableObserver, 這次不一樣的是上游變成了Flowable, 下游變成了Subscriber, 但是水管之間的連接還是通過subscribe(), 我們來看看最基本的用法吧:

Flowable<Integer> upstream = Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
                Log.d(TAG, "emit 1");
                emitter.onNext(1);
                Log.d(TAG, "emit 2");
                emitter.onNext(2);
                Log.d(TAG, "emit 3");
                emitter.onNext(3);
                Log.d(TAG, "emit complete");
                emitter.onComplete();
            }
        }, BackpressureStrategy.ERROR); //增加了一個參數

        Subscriber<Integer> downstream = new Subscriber<Integer>() {

            @Override
            public void onSubscribe(Subscription s) {
                Log.d(TAG, "onSubscribe");
                s.request(Long.MAX_VALUE);  //注意這句代碼
            }

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

            }

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

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

        upstream.subscribe(downstream);

這段代碼中,分別創建了一個上游Flowable和下游Subscriber, 上下游工作在同一個線程中, 和之前的Observable的使用方式只有一點點的區別, 先來看看運行結果吧:

D/TAG: onSubscribe   
D/TAG: emit 1        
D/TAG: onNext: 1     
D/TAG: emit 2        
D/TAG: onNext: 2     
D/TAG: emit 3        
D/TAG: onNext: 3     
D/TAG: emit complete 
D/TAG: onComplete

結果也和我們預期的是一樣的.

我們注意到這次和Observable有些不同. 首先是創建Flowable的時候增加了一個參數, 這個參數是用來選擇背壓,也就是出現上下游流速不均衡的時候應該怎麼處理的辦法, 這裏我們直接用BackpressureStrategy.ERROR這種方式, 這種方式會在出現上下游流速不均衡的時候直接拋出一個異常,這個異常就是著名的MissingBackpressureException. 其餘的策略後面再來講解.

另外的一個區別是在下游的onSubscribe方法中傳給我們的不再是Disposable了, 而是Subscription, 它倆有什麼區別呢, 首先它們都是上下游中間的一個開關, 之前我們說調用Disposable.dispose()方法可以切斷水管, 同樣的調用Subscription.cancel()也可以切斷水管, 不同的地方在於Subscription增加了一個void request(long n)方法, 這個方法有什麼用呢, 在上面的代碼中也有這麼一句代碼:

s.request(Long.MAX_VALUE);  
這句代碼有什麼用呢, 不要它可以嗎? 我們來試試:
這次我們取消掉了request這句代碼, 來看看運行結果:
zlc.season.rxjava2demo D/TAG: onSubscribe
zlc.season.rxjava2demo D/TAG: emit 1
zlc.season.rxjava2demo W/TAG: onError: 
                              io.reactivex.exceptions.MissingBackpressureException: create: could not emit value due to lack of requests
                                  at io.reactivex.internal.operators.flowable.FlowableCreate$ErrorAsyncEmitter.onOverflow(FlowableCreate.java:411)
                                  at io.reactivex.internal.operators.flowable.FlowableCreate$NoOverflowBaseAsyncEmitter.onNext(FlowableCreate.java:377)
                                  at zlc.season.rxjava2demo.demo.ChapterSeven$3.subscribe(ChapterSeven.java:77)
                                  at io.reactivex.internal.operators.flowable.FlowableCreate.subscribeActual(FlowableCreate.java:72)
                                  at io.reactivex.Flowable.subscribe(Flowable.java:12218)
                                  at zlc.season.rxjava2demo.demo.ChapterSeven.demo2(ChapterSeven.java:111)
                                  at zlc.season.rxjava2demo.MainActivity$2.onClick(MainActivity.java:36)
                                  at android.view.View.performClick(View.java:5637)
                                  at android.view.View$PerformClick.run(View.java:22429)
                                  at android.os.Handler.handleCallback(Handler.java:751)
                                  at android.os.Handler.dispatchMessage(Handler.java:95)
                                  at android.os.Looper.loop(Looper.java:154)
                                  at android.app.ActivityThread.main(ActivityThread.java:6119)
                                  at java.lang.reflect.Method.invoke(Native Method)
                                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
zlc.season.rxjava2demo D/TAG: emit 2
zlc.season.rxjava2demo D/TAG: emit 3
zlc.season.rxjava2demo D/TAG: emit complete

從運行結果中可以看到, 在上游發送第一個事件之後, 下游就拋出了一個著名的MissingBackpressureException異常, 並且下游沒有收到任何其餘的事件. 可是這是一個同步的訂閱呀, 上下游工作在同一個線程, 上游每發送一個事件應該會等待下游處理完了纔會繼續發事件啊, 不可能出現上下游流速不均衡的問題呀.

帶着這個疑問, 我們再來看看異步的情況:

Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
                Log.d(TAG, "emit 1");
                emitter.onNext(1);
                Log.d(TAG, "emit 2");
                emitter.onNext(2);
                Log.d(TAG, "emit 3");
                emitter.onNext(3);
                Log.d(TAG, "emit complete");
                emitter.onComplete();
            }
        }, BackpressureStrategy.ERROR).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {

                    @Override
                    public void onSubscribe(Subscription s) {
                        Log.d(TAG, "onSubscribe");
                        mSubscription = s;
                    }

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

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

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

這次我們同樣去掉了request這句代碼, 但是讓上下游工作在不同的線程, 來看看運行結果:
zlc.season.rxjava2demo D/TAG: onSubscribe
zlc.season.rxjava2demo D/TAG: emit 1
zlc.season.rxjava2demo D/TAG: emit 2
zlc.season.rxjava2demo D/TAG: emit 3
zlc.season.rxjava2demo D/TAG: emit complete

哎, 這次上游正確的發送了所有的事件, 但是下游一個事件也沒有收到. 這是因爲什麼呢?

這是因爲Flowable在設計的時候採用了一種新的思路也就是響應式拉取的方式來更好的解決上下游流速不均衡的問題, 與我們之前所講的控制數量控制速度不太一樣, 這種方式用通俗易懂的話來說就好比是葉問打鬼子, 我們把上游看成小日本, 把下游當作葉問, 當調用Subscription.request(1)時, 葉問就說我要打一個! 然後小日本就拿出一個鬼子給葉問, 讓他打, 等葉問打死這個鬼子之後, 再次調用request(10), 葉問就又說我要打十個! 然後小日本又派出十個鬼子給葉問, 然後就在邊上看熱鬧, 看葉問能不能打死十個鬼子, 等葉問打死十個鬼子後再繼續要鬼子接着打...

所以我們把request當做是一種能力, 當成下游處理事件的能力, 下游能處理幾個就告訴上游我要幾個, 這樣只要上游根據下游的處理能力來決定發送多少事件, 就不會造成一窩蜂的發出一堆事件來, 從而導致OOM. 這也就完美的解決之前我們所學到的兩種方式的缺陷, 過濾事件會導致事件丟失, 減速又可能導致性能損失. 而這種方式既解決了事件丟失的問題, 又解決了速度的問題, 完美 !

但是太完美的東西也就意味着陷阱也會很多, 你可能只是被它的外表所迷惑, 失去了理智, 如果你濫用或者不遵守規則, 一樣會吃到苦頭.

比如這裏需要注意的是, 只有當上游正確的實現了如何根據下游的處理能力來發送事件的時候, 才能達到這種效果, 如果上游根本不管下游的處理能力, 一股腦的瞎他媽發事件, 仍然會產生上下游流速不均衡的問題, 這就好比小日本管他葉問要打幾個, 老子直接拿出1萬個鬼子, 這尼瑪有種打死給我看看? 那麼如何正確的去實現上游呢, 這裏先賣個關子, 之後我們再來講解.

學習了request, 我們就可以解釋上面的兩段代碼了

首先第一個同步的代碼, 爲什麼上游發送第一個事件後下遊就拋出了MissingBackpressureException異常, 這是因爲下游沒有調用request, 上游就認爲下游沒有處理事件的能力, 而這又是一個同步的訂閱, 既然下游處理不了, 那上游不可能一直等待吧, 如果是這樣, 萬一這兩根水管工作在主線程裏, 界面不就卡死了嗎, 因此只能拋個異常來提醒我們. 那如何解決這種情況呢, 很簡單啦, 下游直接調用request(Long.MAX_VALUE)就行了, 或者根據上游發送事件的數量來request就行了, 比如這裏request(3)就可以了.

然後我們再來看看第二段代碼, 爲什麼上下游沒有工作在同一個線程時, 上游卻正確的發送了所有的事件呢? 這是因爲在Flowable裏默認有一個大小爲128的水缸, 當上下游工作在不同的線程中時, 上游就會先把事件發送到這個水缸中, 因此, 下游雖然沒有調用request, 但是上游在水缸中保存着這些事件, 只有當下遊調用request時, 才從水缸裏取出事件發給下游.

是不是這樣呢, 我們來驗證一下:

public static void request(long n) {
        mSubscription.request(n); //在外部調用request請求上游
    }

    public static void demo3() {
        Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
                Log.d(TAG, "emit 1");
                emitter.onNext(1);
                Log.d(TAG, "emit 2");
                emitter.onNext(2);
                Log.d(TAG, "emit 3");
                emitter.onNext(3);
                Log.d(TAG, "emit complete");
                emitter.onComplete();
            }
        }, BackpressureStrategy.ERROR).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {

                    @Override
                    public void onSubscribe(Subscription s) {
                        Log.d(TAG, "onSubscribe");
                        mSubscription = s;  //把Subscription保存起來
                    }

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

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

                    @Override
                    public void onComplete() {
                        Log.d(TAG, "onComplete");
                    }
                });
    }
這裏我們把Subscription保存起來, 在界面上增加了一個按鈕, 點擊一次就調用Subscription.request(1), 來看看運行結果:


結果似乎像那麼回事, 上游發送了四個事件保存到了水缸裏, 下游每request一個, 就接收一個進行處理.

剛剛我們有說到水缸的大小爲128, 有朋友就問了, 你說128就128嗎, 又不是唯品會週年慶, 我不信. 那就來驗證一下:

Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
                for (int i = 0; i < 128; i++) {
                    Log.d(TAG, "emit " + i);
                    emitter.onNext(i);
                }
            }
        }, BackpressureStrategy.ERROR).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {

                    @Override
                    public void onSubscribe(Subscription s) {
                        Log.d(TAG, "onSubscribe");
                        mSubscription = s;
                    }

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

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

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


這裏我們讓上游一次性發送了128個事件, 下游一個也不接收, 來看看運行結果:
zlc.season.rxjava2demo D/TAG: onSubscribe
zlc.season.rxjava2demo D/TAG: emit 0
  ...
zlc.season.rxjava2demo D/TAG: emit 126
zlc.season.rxjava2demo D/TAG: emit 127


這段代碼的運行結果很正常, 沒有任何錯誤和異常, 上游僅僅是發送了128個事件.

那來試試129個呢, 把上面代碼中的128改成129試試:

zlc.season.rxjava2demo D/TAG: onSubscribe
zlc.season.rxjava2demo D/TAG: emit 0
  ...
zlc.season.rxjava2demo D/TAG: emit 126
zlc.season.rxjava2demo D/TAG: emit 127
zlc.season.rxjava2demo D/TAG: emit 128  //這是第129個事件
zlc.season.rxjava2demo W/TAG: onError: 
                              io.reactivex.exceptions.MissingBackpressureException: create: could not emit value due to lack of requests
                                  at io.reactivex.internal.operators.flowable.FlowableCreate$ErrorAsyncEmitter.onOverflow(FlowableCreate.java:411)
                                  at io.reactivex.internal.operators.flowable.FlowableCreate$NoOverflowBaseAsyncEmitter.onNext(FlowableCreate.java:377)
                                  at zlc.season.rxjava2demo.demo.ChapterSeven$7.subscribe(ChapterSeven.java:169)
                                  at io.reactivex.internal.operators.flowable.FlowableCreate.subscribeActual(FlowableCreate.java:72)
                                  at io.reactivex.Flowable.subscribe(Flowable.java:12218)
                                  at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82)
                                  at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)
                                  at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
                                  at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                                  at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
                                  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
                                  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
                                  at java.lang.Thread.run(Thread.java:761)

這次可以看到, 在上游發送了第129個事件的時候, 就拋出了MissingBackpressureException異常, 提醒我們發洪水啦. 當然了, 這個128也不是我憑空捏造出來的, Flowable的源碼中就有這個buffersize的大小定義, 可以自行查看.

注意這裏我們是把上游發送的事件全部都存進了水缸裏, 下游一個也沒有消費, 所以就溢出了, 如果下游去消費了事件, 可能就不會導致水缸溢出來了. 這裏我們說的是可能不會, 這也很好理解, 比如剛纔這個例子上游發了129個事件, 下游只要快速的消費了一個事件, 就不會溢出了, 但如果下游過了十秒鐘再來消費一個, 那肯定早就溢出了.


我們先來思考一下, 發送128個事件沒有問題是因爲FLowable內部有一個大小爲128的水缸, 超過128就會裝滿溢出來, 那既然你水缸這麼小, 那我給你換一個大水缸如何, 聽上去很有道理的樣子, 來試試:
Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
                for (int i = 0; i < 1000; i++) {
                    Log.d(TAG, "emit " + i);
                    emitter.onNext(i);
                }
            }
        }, BackpressureStrategy.BUFFER).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {

                    @Override
                    public void onSubscribe(Subscription s) {
                        Log.d(TAG, "onSubscribe");
                        mSubscription = s;
                    }

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

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

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


這次我們直接讓上游發送了1000個事件,下游仍然不調用request去請求, 與之前不同的是, 這次我們用的策略是BackpressureStrategy.BUFFER, 這就是我們的新水缸啦, 這個水缸就比原來的水缸牛逼多了,如果說原來的水缸是95式步槍, 那這個新的水缸就好比黃金AK , 它沒有大小限制, 因此可以存放許許多多的事件.

所以這次的運行結果就是:


zlc.season.rxjava2demo D/TAG: onSubscribe
zlc.season.rxjava2demo D/TAG: emit 0
zlc.season.rxjava2demo D/TAG: emit 1
zlc.season.rxjava2demo D/TAG: emit 2
...
zlc.season.rxjava2demo D/TAG: emit 997
zlc.season.rxjava2demo D/TAG: emit 998
zlc.season.rxjava2demo D/TAG: emit 999

不知道大家有沒有發現, 換了水缸的FLowable和Observable好像是一樣的嘛...

不錯, 這時的FLowable表現出來的特性的確和Observable一模一樣, 因此, 如果你像這樣單純的使用FLowable, 同樣需要注意OOM的問題, 例如下面這個例子:

Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
                for (int i = 0; ; i++) {
                    emitter.onNext(i);
                }
            }
        }, BackpressureStrategy.BUFFER).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {

                    @Override
                    public void onSubscribe(Subscription s) {
                        Log.d(TAG, "onSubscribe");
                        mSubscription = s;
                    }

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

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

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


按照我們以前學習Observable一樣, 讓上游無限循環發送事件, 下游一個也不去處理, 來看看運行結果吧:




同樣可以看到, 內存迅速增長, 直到最後拋出OOM. 所以說不要迷戀FLowable, 它只是個傳說.

可能有朋友也注意到了, 之前使用Observable測試的時候內存增長非常迅速, 幾秒鐘就OOM, 但這裏增長速度卻比較緩慢, 可以翻回去看之前的文章中的GIF圖進行對比, 這也看出FLowable相比Observable, 在性能方面有些不足, 畢竟FLowable內部爲了實現響應式拉取做了更多的操作, 性能有所丟失也是在所難免, 因此單單只是說因爲FLowable是新興產物就盲目的使用也是不對的, 也要具體分場景,

那除了給FLowable換一個大水缸還有沒有其他的辦法呢, 因爲更大的水缸也只是緩兵之計啊, 動不動就OOM給你看.


想想看我們之前學習Observable的時候說到的如何解決上游發送事件太快的, 有一招叫從數量上取勝, 同樣的FLowable中也有這種方法, 對應的就是BackpressureStrategy.DROPBackpressureStrategy.LATEST這兩種策略.

從名字上就能猜到它倆是幹啥的, Drop就是直接把存不下的事件丟棄,Latest就是隻保留最新的事件, 來看看它們的實際效果吧.

先來看看Drop:


public static void request() {
        mSubscription.request(128);
    }

public static void demo3() {
        Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
                for (int i = 0; ; i++) {
                    emitter.onNext(i);
                }
            }
        }, BackpressureStrategy.DROP).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {

                    @Override
                    public void onSubscribe(Subscription s) {
                        Log.d(TAG, "onSubscribe");
                        mSubscription = s;
                    }

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

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

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

我們仍然讓上游無限循環發送事件, 這次的策略選擇了Drop, 同時把Subscription保存起來, 待會我們在外部調用request(128)時, 便可以看到運行的結果.

我們先來猜一下運行結果, 這裏爲什麼request(128)呢, 因爲之前不是已經說了嗎, FLowable內部的默認的水缸大小爲128, 因此, 它剛開始肯定會把0-127這128個事件保存起來, 然後丟棄掉其餘的事件, 當我們request(128)的時候,下游便會處理掉這128個事件, 那麼上游水缸中又會重新裝進新的128個事件, 以此類推, 來看看運行結果吧:



從運行結果中我們看到的確是如此, 第一次request的時候, 下游的確收到的是0-127這128個事件, 但第二次request的時候就不確定了, 因爲上游一直在發送事件. 內存佔用也很正常, drop的作用相信大家也很清楚了.

再來看看Latest吧:

public static void request() {
        mSubscription.request(128);
    }

public static void demo4() {
        Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
                for (int i = 0; ; i++) {
                    emitter.onNext(i);
                }
            }
        }, BackpressureStrategy.LATEST).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {

                    @Override
                    public void onSubscribe(Subscription s) {
                        Log.d(TAG, "onSubscribe");
                        mSubscription = s;
                    }

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

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

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


同樣的, 上游無限循環發送事件, 策略選擇Latest, 同時把Subscription保存起來, 方便在外部調用request(128).來看看這次的運行結果:



誒, 看上去好像和Drop差不多啊, Latest也首先保存了0-127這128個事件, 等下游把這128個事件處理了之後才進行之後的處理, 光從這裏沒有看出有任何區別啊...

我們把上面兩段代碼改良一下, 先來看看DROP的改良版:

Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
                for (int i = 0; i < 10000; i++) {  //只發1w個事件
                    emitter.onNext(i);
                }
            }
        }, BackpressureStrategy.DROP).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {

                    @Override
                    public void onSubscribe(Subscription s) {
                        Log.d(TAG, "onSubscribe");
                        mSubscription = s;
                        s.request(128);  //一開始就處理掉128個事件
                    }

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

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

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

這段代碼和之前有兩點不同, 一是上游只發送了10000個事件, 二是下游在一開始就立馬處理掉了128個事件, 然後我們在外部再調用request(128)試試, 來看看運行結果:


這次可以看到, 一開始下游就處理掉了128個事件, 當我們再次request的時候, 只得到了第3317的事件, 後面的事件直接被拋棄了.

再來看看Latest的運行結果吧:

從運行結果中可以看到, 除去前面128個事件, 與Drop不同, Latest總是能獲取到最後最新的事件, 例如這裏我們總是能獲得最後一個事件9999.

好了, 關於FLowable的策略我們也講完了, 有些朋友要問了, 這些FLowable是我自己創建的, 所以我可以選擇策略, 那面對有些FLowable並不是我自己創建的, 該怎麼辦呢? 比如RxJava中的interval操作符, 這個操作符並不是我們自己創建的, 來看下面這個例子吧:

Flowable.interval(1, TimeUnit.MICROSECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Long>() {
                    @Override
                    public void onSubscribe(Subscription s) {
                        Log.d(TAG, "onSubscribe");
                        mSubscription = s;
                        s.request(Long.MAX_VALUE);
                    }

                    @Override
                    public void onNext(Long aLong) {
                        Log.d(TAG, "onNext: " + aLong);
                        try {
                            Thread.sleep(1000);  //延時1秒
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

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

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



interval操作符發送Long型的事件, 從0開始, 每隔指定的時間就把數字加1併發送出來, 在這個例子裏, 我們讓它每隔1毫秒就發送一次事件, 在下游延時1秒去接收處理, 不用猜也知道結果是什麼:


zlc.season.rxjava2demo D/TAG: onSubscribe
zlc.season.rxjava2demo W/TAG: onError: 
                              io.reactivex.exceptions.MissingBackpressureException: Can't deliver value 128 due to lack of requests
                                  at io.reactivex.internal.operators.flowable.FlowableInterval$IntervalSubscriber.run(FlowableInterval.java:87)
                                  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
                                  at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:278)
                                  at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:273)
                                  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
                                  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
                                  at java.lang.Thread.run(Thread.java:761)


一運行就拋出了MissingBackpressureException異常, 提醒我們發太多了, 那麼怎麼辦呢, 這個又不是我們自己創建的FLowable啊...

別慌, 雖然不是我們自己創建的, 但是RxJava給我們提供了其他的方法:

  • onBackpressureBuffer()
  • onBackpressureDrop()
  • onBackpressureLatest()

熟悉嗎? 這跟我們上面學的策略是一樣的, 用法也簡單, 拿剛纔的例子現學現用:



Flowable.interval(1, TimeUnit.MICROSECONDS)
                .onBackpressureDrop()  //加上背壓策略
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Long>() {
                    @Override
                    public void onSubscribe(Subscription s) {
                        Log.d(TAG, "onSubscribe");
                        mSubscription = s;
                        s.request(Long.MAX_VALUE);
                    }

                    @Override
                    public void onNext(Long aLong) {
                        Log.d(TAG, "onNext: " + aLong);
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

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

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

注:本文總結自Season_zlc的給初學者的RxJava2.0教程

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