Rxjava2最全面的解析

我就是馬雲飛發表於2019-03-04

前言

由於公司重新規劃的部門,我調到了另外一個部門,所以負責的專案也換了,仔細看了下整體的專案,rxjava+retrofit。整體的一套。眾所周知,rxjava+retrofit是目前網上最流行的網路解析框架。而目前網路上的文章大多還是關於rxjava1的。關於RxJava2的少之又少,於是,便有了此文。

此文的目的有三個: 1. 給對 RxJava2感興趣的人一些入門的指引 2. 給正在使用 RxJava2但仍然心存疑惑的人一些更深入的解析 3.給想從RxJava1替換成RxJava2的人給出直接的對比。

RxJava概念介紹

RxJava=reactive+extension。 那麼接下來我會分別對這兩點進行整體的介紹。reactive又稱reactive programming。也就是響應式程式設計。在往簡單的說,rxjava可以很方便的處理執行緒切換的問題。說到這個,我們就會想到非同步操作。handler?AsyncTask?但你要知道,隨著請求的數量越來越多,程式碼邏輯將會變得越來越複雜。而rxjava卻仍可以保持清晰的邏輯。它的原理就是建立一個Observable物件來搞事情。然後使用各種操作符通過建造者模式建立成一系列的鏈式操作。就如流水線一樣,把事情搞完。然後發射給Observer進行處理。

觀察者模式

rxjava的實現主要是通過觀察者模式實現的。那麼什麼是觀察者模式,我這邊做一個簡單的介紹。

栗子:觀察者對被觀察者進行一個簡單,當被觀察者被改變時,要立即做出反應。比如,你認為隔壁老王和你媳婦有一腿,但卻沒證據,此時,只要當隔壁老王進了你媳婦房門的時候,你就要去捕獲他。在這個例子中,你是觀察者,老王是被觀察者。(記得當初我經常搞反了)。那麼,觀察者模式是否是一對一呢?很明顯不是的,就上面的例子,你可以叫三千城管監聽著老王。只要他有不軌之心。就打斷他的第三條腿。也就是說多個觀察者對應一個被觀察者。字看累了來看圖:

Rxjava2最全面的解析

其實在android中也有很多自帶的觀察者模式。最明顯的莫過於點選事件。說個最簡單的例子,點選按鈕後彈一個吐司。那麼,我們在點選按鈕的時候,告知系統,此時,我需要彈一個吐司。那麼就這麼彈出來了。那麼,這個時候問題來了。我是否需要實時去監聽這個按鈕呢?答案是不需要的。這就和前面的舉例有的差距了。換句話說。我只要在此按鈕進行點選時進行監聽就可以了。這種操作被稱為訂閱。也就是說Button通過setOnClickListener對OnclickListener進行了訂閱了操作,來監聽onclick方法。

extension

  • 不僅支援事件序列,還支援資料流。事件-->動態的,無法預知,例如:事件點選,伺服器的推送等等 資料流-->靜態的,可預知的,例如:讀取本地檔案,播放音視訊等等。

  • 通過操作符對中間事件的處理。

  • 執行緒操作的便捷。關於這些具體的實現。我會在後面一一舉例。

RxJava1與RxJava2的區別

說到區別,可能有的小夥伴會問,我沒看過rxjava1。可以直接看rxjava2麼。個人覺得不必要,因為 rxjava2.x 是按照 Reactive-Streams specification 規範完全的重寫的,完全獨立於 rxjava1.x 而存在,它改變了以往 rxjava1的用法。換句話說,我學java需不需要先學C語言一樣。

那麼兩者的區別體現在哪呢?主要是如下幾個方面:

  • 空指標問題這應該是一個很大的變化,用過rxjava1的人都知道,我們可以在發射事件的時候傳入NULL。但這在rxjava2中是不存在的。不信你試試?分分鐘給你來一個NullPointerExpection。

  • Function相關的在rxjava1中,我們有各種Func1,Func2......,但在rxjava2中只有Function了。依舊記得看凱哥的文章的時候把我整蒙了。愣是沒發現,後來才注意到被替換了。並且,他們都增加了throw exception。

  • 背壓—backpressure 關於backpressure,這個就厲害了。厲害到我都不懂了。好了,開個玩笑,我們繼續說。我們知道在Rxjava1中Observable對backpressure是支援的。但在Rxjava2中Observable取消了對backpressure的支援。並且引進了一個叫做Flowable的來支援backpressure。

那麼什麼是背壓: 聽不懂的含義:上游的生產速度大於下游的處理速度,導致下游處理不急,這種操作被稱為backpressure。

這種情況看似很常見,但實際上,這種情況並不常見,或者可以說成非常罕見。那麼遇到了怎麼辦?如果它出現了,直接丟棄。what the fuck?你tm在逗我?但事實就是這樣,如果我們在開發過程中,遇到了backpressure,我們就應該丟棄它。

聽得懂的含義:對於可丟棄的事件,上游生產速度過快導致事件堆積,當堆積到超出buffer上限的時候,就叫做backpressure。

處理方案是什麼: 1、丟棄新事件;2、不丟棄,繼續堆積。(忽略了backpressure,相當於Observable)。

適合backpressure的情況: 線上直播流:比如說,正在直播的時候,突然網路出現了卡頓,頁面卡住了。那麼當網路好了之後肯定不會是在接著之前的頁面繼續的,就相當於,你網路卡了多久,他就丟棄了多長時間的資料。

backpressure的關鍵點是什麼:不可控,可丟棄。

基本使用

講了一大堆理念知識,接下來就是開工幹活了。那麼關於Rxjava2的基本實現主要是三點:建立Observable,建立Observer,進行繫結。那麼我們一個個的看。

建立Observable

Observable是什麼?觀察者還是被觀察者?我又忘了。哈哈。開個玩笑,當然是後者了。為什麼是先建立Observable而不是Observer?當然了,先後順序的無所謂的。但是考慮到後面的鏈式呼叫。所以我這邊就先寫了先建立Observable了。

Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("Hello");
                emitter.onNext("Rxjava2");
                emitter.onNext("My name is Silence");
                emitter.onNext("What's your name");
                //一旦呼叫onComplete,下面將不在接受事件
                emitter.onComplete();
            }
        });複製程式碼

現在我來解釋一下上面的ObservableEmitter到底是什麼。字面意思是可觀察的發射器。沒錯,這個就是被觀察者用來傳送事件的。它可以發出三種型別的事件,通過呼叫emitter的onNext(T value)、onError(Throwable error)和onComplete()就可以分別發出next事件、error事件和complete事件。至於這三個事件到底什麼意思。不急,我們後面說。

建立Observer

現在我們來建立一個觀察者,它決定了在觀察中到底應該有著什麼樣的行為操作。

        Observer<String> observer = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.i(TAG, "onSubscribe: " + d);
                result += "onSubscribe: " + d + "\n";
            }
​
            @Override
            public void onNext(String string) {
                Log.i(TAG, "onNext: " + string);
                result += "onNext: " + string + "\n";
            }
​
            @Override
            public void onError(Throwable e) {
                Log.i(TAG, "onError: " + e);
                result += "onError: " + e + "\n";
            }
​
            @Override
            public void onComplete() {
                Log.i(TAG, "onComplete: ");
                result += "onComplete: " + "\n";
            }
        };複製程式碼

其中onSubscribe、onNext、onError和onComplete是必要的實現方法,其含義如下:

  • onSubscribe:它會在事件還未傳送之前被呼叫,可以用來做一些準備操作。而裡面的Disposable則是用來切斷上下游的關係的。

  • onNext:普通的事件。將要處理的事件新增到佇列中。

  • onError:事件佇列異常,在事件處理過程中出現異常情況時,此方法會被呼叫。同時佇列將會終止,也就是不允許在有事件發出。

  • onComplete:事件佇列完成。rxjava不僅把每個事件單獨處理。而且會把他們當成一個佇列。當不再有onNext事件發出時,需要觸發onComplete方法作為完成標識。

進行Subscribe

訂閱其實只需要一行程式碼就夠了:

observerable.subscribe(Observer);複製程式碼

執行一個看看效果先:Rxjava2最全面的解析

和之前介紹的一樣,先呼叫onSubscribe,然後走了onNext,最後以onComplete收尾。

神奇的操作符

對於rxjava來說,有一句話,我覺得說的很對,叫做:如果你每天研究一個操作符,最少一個半月,如果你想理解原理。最少半年。換句話說,有關rxjava的知識完全可以寫一本書。那麼本文肯定不會講那麼細。在這邊我會給你們介紹一些常用的操作符。保證日常開發的流程足矣。

建立操作符

一般建立操作符是指,剛開始建立觀察者的時候呼叫的。在基本使用中我已經介紹了create操作符,那麼這邊我們就要說到just,fromarray和interval了。

just

此操作符是將傳入的引數依次發出來。

Observable observable = Observable.just("Hello", "Rxjava2", "My name is Silence","What's your name");
// 將會依次呼叫:
// onNext("Hello");
// onNext("Rxjava2");
// onNext("My name is Silence");
// onNext("What's your name");
// onCompleted();複製程式碼
fromarray

將傳入的陣列通過座標一次傳送出去。

String[] words = {"Hello", "Rxjava2", "My name is Silence","What's your name"};
Observable observable = Observable.from(words);
// 將會依次呼叫:
// onNext("Hello");
// onNext("Rxjava2");
// onNext("My name is Silence");
// onNext("What's your name");
// onCompleted();複製程式碼
interval

這個其實就是定時器,用了它你可以拋棄CountDownTimer了。現在我們看看怎麼用:

 Observable.interval(2, TimeUnit.SECONDS).subscribe(
                new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        Log.i(TAG, "accept: "+aLong.intValue());
                    }
                }
        );複製程式碼

我們看看結果:

Rxjava2最全面的解析

上面就是我們每隔2s列印一次long的值。

變換操作符

變換操作符的作用是對Observable發射的資料按照一定規則做一些變換操作,然後講變換後的資料發射出去。變換操作符有map,flatMap,concatMap,switchMap,buffer,groupBy等等。這裡我們會講解最常用的map,flatMap、concatMap以及compose。

map

map操作符通過指定一個Function物件,將Observable轉換為一個新的Observable物件併發射,觀察者將收到新的Observable處理。直接上程式碼:

  Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
                emitter.onNext(4);
            }
        }).map(new Function<Integer, String>() {
            @Override
            public String apply(Integer integer) throws Exception {
                return "This is result " + integer + "\n";
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String str) throws Exception {
                Log.i("--->", "accept: "+str);
                string += str;
            }
        });
        tv_first.setText(string);複製程式碼

輸入結果如下:

Rxjava2最全面的解析

仔細看,map()方法中,我們把一個integer物件轉換成了一個String物件。然後當map()呼叫結束時,事件的引數型別也從integer轉換成了String。這就是最常見的變換操作。

flatMap

flatmap的操作符是將Observable發射的資料集合變成一個Observable集合。也就是說它可以講一個觀察物件變換成多個觀察物件,但是並不能保證事件的順序。想保證事件的順序?那你過會看下面降到的concatMap。

那麼什麼叫作資料集合變成一個Observable集合呢?還是用上面的例子,我有一組integer集合。我想轉換成string集合怎麼辦?那就繼續看程式碼:

  Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }
        }).flatMap(new Function<Integer, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(Integer integer) throws Exception {
                final List<String> list = new ArrayList<>();
                for (int i = 0; i < 3; i++) {
                    list.add("I am value " + integer + "\n");
                }
                return Observable.fromIterable(list);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.i("--->", "accept: "+s);
                string += s;
            }
        });
        tv_first.setText(string);複製程式碼

我們來看結果:

Rxjava2最全面的解析

打住打住,是不是有問題?WTF?有啥問題?還記不記得我上面說過flatMap不能保證事件執行順序。那麼這邊事件為什麼都是按順序執行的?不急,我們在發射事件的時候給他加一個延遲在看看結果:

 Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }
        }).flatMap(new Function<Integer, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(Integer integer) throws Exception {
                final List<String> list = new ArrayList<>();
                for (int i = 0; i < 3; i++) {
                    list.add("I am value " + integer + "\n");
                }
                return Observable.fromIterable(list).delay(100,TimeUnit.MILLISECONDS);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.i("--->", "accept: "+s);
                string += s;
            }
        });
        tv_first.setText(string);複製程式碼

我們在當他發射事件的時候給他加一個100ms的延遲看看結果:

Rxjava2最全面的解析

看到沒有,我說啥的?不能保證執行順序。所以萬事容我慢慢道來。先喝杯茶壓壓驚。我們在接著往下講。

concatMap

上面我也介紹了concatMap。除了保證了執行順序,其他都和concatMap一毛一樣。你說保證就保證啊。您先喝杯茶,接著往下看:

 Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }
        }).concatMap(new Function<Integer, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(Integer integer) throws Exception {
                final List<String> list = new ArrayList<>();
                for (int i = 0; i < 3; i++) {
                    list.add("I am value " + integer + "\n");
                }
                return Observable.fromIterable(list).delay(1000,TimeUnit.MILLISECONDS);
//                return Observable.fromIterable(list);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.i("--->", "accept: "+s);
                string += s;
            }
        });
        tv_first.setText(string);複製程式碼

為了我們能看的更明顯一點,我這邊直接設定了一秒鐘的延遲。下面我們來看效果圖:

Rxjava2最全面的解析

可以從執行順序和列印時間看出,的的確確是延遲了一秒鐘。

compose

這個操作符就很厲害了。他的變換是怎麼做的呢?我們知道rxjava是通過建造者的模式通過鏈式來呼叫起來的。那麼多個鏈式就需要多個Observable。而這個操作符就是把多個Observable轉化成一個Observable。聽起來是不是很厲害~。具體如何操作,我們接著看:

​
    public  <T> ObservableTransformer<T, T> applyObservableAsync() {
        return new ObservableTransformer<T, T>() {
            @Override
            public ObservableSource<T> apply(Observable<T> upstream) {
                return upstream.subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }複製程式碼

上面程式碼可以看出,我把子執行緒和主執行緒進行了一個封裝,然後返回了一個ObservableTransformer物件。那麼我們只要這邊做就可以了:

    Observable.just(1, 2, 3, 4, 5, 6)
                .compose(this.<Integer>applyObservableAsync())
                .subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer strings) throws Exception {
                Log.i("-->", "accept: " + strings);
                string += strings;
            }
        });
        tv_first.setText(string);複製程式碼

過濾操作符

過濾操作符用於過濾和選擇Observable發射的資料序列。讓Observable只返回滿足我們條件的資料。過濾操作符有buffer,filter,skip,take,skipLast,takeLast等等,這邊我會介紹到filter,buffer,skip,take,distinct。

filter

filter操作符是對源Observable產生的結果進行有規則的過濾。只有滿足規則的結果才會提交到觀察者手中。例如:

   Observable.just(1,2,3).filter(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) throws Exception {
                return integer < 3;
            }
        }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer s) throws Exception {
                Log.i("--->", "accept: " + s);
                string += s;
            }
        });
        tv_first.setText(string);
    }複製程式碼

程式碼很簡單,我們傳送1,2,3;但是我們加上一個filter操作符,讓它只返回小於3的的內容。那麼我們來看一下結果:

Rxjava2最全面的解析

distinct

這個操作符其實就更簡單了。比如說,我要在一組資料中去掉重複的內容,就要用到它。也就是去重。它只允許還沒有發射的資料項通過。發射過的資料項直接pass。

        Observable.just(1,2,3,4,2,3,5,6,1,3)
                .distinct().subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer s) throws Exception {
                Log.i("--->", "accept: " + s);
                string += s;
            }
        });
        tv_first.setText(string);複製程式碼

那麼輸出結果就很簡單了:

Rxjava2最全面的解析

buffer

這個其實也不難,主要是快取,把源Observable轉換成一個新的Observable。這個新的Observable每次發射的是一組List,而不是單獨的一個個的傳送資料來源。

  Observable.just(1,2,3,4,5,6)
                .buffer(2).subscribe(new Consumer<List<Integer>>() {
            @Override
            public void accept(List<Integer> strings) throws Exception {
                for (Integer integer : strings) {
                    Log.i("-->", "accept: "+integer);
                    string+=strings;
                }
                Log.i("-->", "accept: ----------------------->");
            }
        });
        tv_first.setText(string);複製程式碼

我們讓他每次快取2個,下面我們來看結果:

Rxjava2最全面的解析

skip 、take

skip操作符將源Observable發射過的資料過濾掉前n項,而take操作則只取前n項;另外還有skipLast和takeLast則是從後往前進行過濾。先來看看skip操作符。

 Observable.just(1, 2, 3, 4, 5, 6)
                .skip(2).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer strings) throws Exception {
                Log.i("-->", "accept: " + strings);
                string += strings;
            }
        });
        tv_first.setText(string);複製程式碼

結果如下:

Rxjava2最全面的解析

接下來我們把skip換成take看看。

 Observable.just(1, 2, 3, 4, 5, 6)
                .take(3).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer strings) throws Exception {
                Log.i("-->", "accept: " + strings);
                string += strings;
            }
        });
        tv_first.setText(string);複製程式碼

結果如下:

Rxjava2最全面的解析

組合操作符

merge

merge是將多個操作符合併到一個Observable中進行發射,merge可能讓合併到Observable的資料發生錯亂。(並行無序)

  Observable<Integer> observable1=Observable.just(1,2,3);
        Observable<Integer> observable2=Observable.just(1,2,3);
        Observable.merge(observable1,observable2).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.i(TAG, "accept: "+integer);
            }
        });複製程式碼

結果如下:

Rxjava2最全面的解析

concat

將多個Observable發射的資料進行合併並且發射,和merge不同的是,merge是無序的,而concat是有序的。(序列有序)沒有發射完前一個它一定不會傳送後一個。

 Observable<Integer> observable1=Observable.just(1,2,3);
        Observable<Integer> observable2=Observable.just(4,5,6);
        Observable.concat(observable1,observable2).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.i(TAG, "accept: "+integer);
            }
        });複製程式碼

結果如下:

Rxjava2最全面的解析

zip

此操作符和合並多個Observable傳送的資料項,根據他們的型別就行重新變換,併發射一個新的值。

  Observable<Integer> observable1=Observable.just(1,2,3);
        Observable<String> observable2=Observable.just("a","b","c");
        Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
​
            @Override
            public String apply(Integer integer, String s) throws Exception {
                return integer+s;
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.i(TAG, "apply: "+s);
            }
        });複製程式碼

結果如下:

Rxjava2最全面的解析

concatEager

前面說道序列有序,而concatEager則是並行且有序。我們來看看如果修改:

 Observable<Integer> observable1=Observable.just(1,2,3);
        Observable<String> observable2=Observable.just("a","b","c");
        Observable.concatEager(Observable.fromArray(observable1,observable2)).subscribe(new Consumer<Serializable>() {
            @Override
            public void accept(Serializable serializable) throws Exception {
                Log.i(TAG, "accept: "+serializable);
            }
        });複製程式碼

結果如下:

Rxjava2最全面的解析

執行緒控制

其實執行緒控制也是一種操作符。但它不屬於建立、變換、過濾。所以我這邊把它單獨拉出來講講。

subscribeOn是指上游傳送事件的執行緒。說白了也就是子執行緒。多次指定上游的執行緒只有第一次指定的有效, 也就是說多次呼叫subscribeOn() 只有第一次的有效, 其餘的會被忽略。

observerOn是指下游接受事件的執行緒。也就是主執行緒。多次指定下游的執行緒是可以的, 也就是說每呼叫一次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() 指定複製程式碼

在RxJava中, 已經內建了很多執行緒選項供我們選擇, 例如有

  • Schedulers.io() :I/O操作(讀寫檔案、資料庫,及網路互動等)所使用的Scheduler。行為模式和newThread()差不多。區別在於io()的內部實現是用一個無數量上限的執行緒池。可以重用空閒的執行緒。因此多數情況下io()比newThread()更有效率。

  • Schedulers.immediate(): 直接在當前執行緒執行。

  • Schedulers.computation() :計算所使用的Scheduler,例如圖形的計算。這個Scheduler使用固定執行緒池,大小為CPU核數。不要把I/O操作放在computation中。否則I/O操作的等待會浪費CPU。

  • Schedulers.newThread():代表一個常規的新執行緒

  • Schedulers.trampoline(): 當我們想線上程執行一個任務時(不是立即執行),可以用此方法將它加入佇列。這個排程器將會處理它的佇列並且按序執行佇列中的每一個任務。

  • AndroidSchedulers.mainThread() :代表Android的主執行緒

這些內建的Scheduler已經足夠滿足我們開發的需求, 因此我們應該使用內建的這些選項, 在RxJava內部使用的是執行緒池來維護這些執行緒, 所有效率也比較高。

與Retrofit結合

就目前開發角度而言,retrofit可以說是最火的網路框架。其原因我認為有兩點,第一:可以和okhttp結合。第二:可以和rxjava結合。也就是說Retrofit 除了提供了傳統的 Callback 形式的 API,還有 RxJava 版本的 Observable 形式 API。

如果需要使用retrofit,我們需要在gradle的配置加上這句:

compile 'com.squareup.retrofit2:retrofit:2.0.1'複製程式碼

話不多說,直接上例子:

​
    private static OkHttpClient mOkHttpClient;
    private static Converter.Factory gsonConverterFactory = GsonConverterFactory.create();
    private static CallAdapter.Factory rxJavaCallAdapterFactory = RxJavaCallAdapterFactory.create();
     public static BaseHttpApi getObserve() {
​
        if (baseHttpApi == null) {
            Retrofit retrofit = new Retrofit.Builder()
                    .addConverterFactory(gsonConverterFactory)
                    .addCallAdapterFactory(rxJavaCallAdapterFactory)
                    .client(mOkHttpClient)
                    .baseUrl(BaseUrl.WEB_BASE)
                    .build();
            baseHttpApi = retrofit.create(BaseHttpApi.class);
       }
        return baseHttpApi;
​
    }複製程式碼

如上程式碼,可以很清晰的看出,它通過2個工廠模式建立了gson和rxjava。並且通過了鏈式呼叫將他們進行了繫結。那麼怎麼通過鏈式呼叫實現網路請求呢?不急,我們喝杯茶,接著往下看。

比如,一個post請求,我們可以這麼寫:

public interface BaseHttpApi{  
    @FormUrlEncoded
    @POST("seller/cash_flow_log_detail.json")
    Observable<ServiceReward> serviceReward(@Field("requestmodel") String model);
}複製程式碼

敲黑板了。注意,我這邊是interface而不是一個class。接下來就是日常呼叫了,程式碼如下:

  Network.getObserve()
                .serviceReward(new Gson().toJson(map))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<ServiceReward>() {
                    @Override
                    public void onCompleted() {
​
                    }
​
                    @Override
                    public void onError(Throwable e) {
​
                    }
​
                    @Override
                    public void onNext(ServiceReward serviceReward) {
                        parseOrderDetail(serviceReward);
                    }
                });複製程式碼

看第二行,這就是為什麼剛開始為什麼要用工廠模式建立gson的原因。現在我們只要在parseOrderDetail方法中處理正常的邏輯就可以了。是不是看起來程式碼有點多?那麼我們可以這樣:

 Network.getObserve()
                .serviceReward(new Gson().toJson(map))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(serviceReward ->{
                        parseOrderDetail(serviceReward);
                 });複製程式碼

一個lamada表示式,是不是感覺瞬間程式碼少了很多,不過有人要說,我載入的時候是一個彈窗顯示的,如果載入失敗了我這個彈窗豈不是影藏不了?不存在的,如果真有這種情況怎麼做?我們接著看:

 Network.getObserve()
                .serviceReward(new Gson().toJson(map))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(serviceReward ->{
                        parseOrderDetail(serviceReward);
                 },throwable ->{do something when net error...});複製程式碼

這麼處理豈不是快哉。對於lamada,剛開始可能都是各種不習慣,不過用習慣了就會發現程式碼各種簡潔(我最近也在適應中)。

最後

關於rxjava其實對我們來說很難上手。或者不能這麼說,應該是rxjava的東西太深了,我們很難掌握透徹。所以我前面也說了如果你每天研究一個操作符,最少一個半月,如果你想理解原理。最少半年。換句話說,有關rxjava的知識完全可以寫一本書。但日常開發中,此文中的內容基本可以解決大部分的日常需求。當然,如果你有心的話,你可以去嘗試著瞭解rxjava底層的實現原理。

Rxjava2最全面的解析


相關文章