Rxjava2(一)、基礎概念及使用

EvanZch發表於2019-12-27

Android進階系列之第三方庫知識點整理。

知識點總結,整理也是學習的過程,如有錯誤,歡迎批評指出。

寫這篇文章的時候,Rxjava3已經出來了,二者差別不是特別大,所以還是基於Rxjava2進行總結,後續會花時間來總結Rxjava3的一些改變。

基礎概念

1、什麼是Rx

ReactiveX是Reactive Extensions的縮寫,一般簡寫為Rx,最初是LINQ的一個擴充套件,Rx是由由微軟開發並開源的一個程式設計模型,目標是提供一致的程式設計介面,幫助開發者更方便的處理非同步資料流,Rx庫支援很多語言,而 Rxjava 是Rx庫基於Java語言提供的函式庫。

官網顯示支援的語言列表:

官網Rx支援的語言
官網Rx支援的語言

2、觀察者模式

觀察者模式(Observer),又叫釋出-訂閱模式(Publish/Subscribe),定義物件間一種一對多的依賴關係,使得每當一個物件改變狀態,則所有依賴於它的物件都會得到通知並自動更新,觀察者模式屬於行為型模式。

我需要打電話跟小明說他被戴綠帽這事,但是我又怕打電話過去他可能在忙,所以我直接給他發資訊,讓他有時間了再給我回電話,這樣,當小明有時間了可能就會給我回電話,他給我回電話,我再含著淚的告訴他要堅強。

在上面這個例子中,小明就是被觀察者,我是觀察者,我發簡訊告訴他有時間回我電話這個操作就是訂閱,這樣我跟他有了依賴關係,當他有時間後,就會回我帶電話,我這邊響應式的執行後續的操作。

3、響應式(Reactive Programming)程式設計

一般來說,程式設計就是為了處理問題,解決問題就可以有不同的視角和思路,其中具有普適性的模式就會歸結一種程式設計思想,我們常說的物件導向,程式導向都是一種程式設計思想。

響應式程式設計是一種通過非同步和資料流來構建事務關係的程式設計模式

這裡麵包含的兩個核心概念:

非同步:不需要等待處理完成便立刻返回,通過回撥將處理結果帶回。能提高吞吐量,提高效能和效率。

資料流:就是按照時間線的事件序列,任何東西都可以看做是一個stream。在這個基礎上通過函式來過濾(filter)、選擇(select)、變換(transform)、結合(combine)這些stream。通過定義事件處理器,來非同步捕獲感興趣的stream,即監聽(訂閱)stream,也叫就是註冊觀察者。

再對比我們前面的觀察者模式看,觀察者模式中被觀察者觀察者之間通過訂閱產生依賴,訂閱這層關係相當於在二者之前挖了一道水渠,被觀察者是上游,觀察者是下游,這樣被觀察者發生改變時候,會將資料流源源不斷的傳送到產生依賴關係的觀察者,通常觀察者被觀察者是處於同一個執行緒中,但是響應式程式設計重點在非同步上,即上游和下游可以在不同的執行緒中工作。

我們可以看一下官網的動圖:

4、Rxjava概念及簡單使用

Rxjava採用了響應式程式設計模式,它在觀察者模式基礎上進行擴充套件,方便我們的非同步操作,觀察者被觀察者產生訂閱關係後,被觀察者將資料流傳送給觀察者的時候,Rxjava提供了豐富的操作符來對資料流進行過濾(filter)、選擇(select)、變換(transform)、結合(combine)等等操作,然後再將處理後的資料傳送給觀察者,又由於其特別棒的鏈式呼叫,讓邏輯在很複雜的情況下,也能很清晰的通過程式碼表達出來。

我們先引入rxjava

implementation "io.reactivex.rxjava2:rxjava:2.2.8"
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
複製程式碼

直接先來一個簡單的例子:

  // 通過 Observable 建立一個被觀察者
  Observable mObservable = Observable.create(new ObservableOnSubscribe() {
         @Override
         public void subscribe(ObservableEmitter emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
                emitter.onComplete();
            }
        });

        // 通過Observer建立一個觀察者
        Observer mObserver = new Observer<Integer>() {
            @Override
            public void onSubscribe(Disposable d) {
                LogUtil.d(TAG + "--onSubscribe");
            }

            @Override
            public void onNext(Integer o) {
                LogUtil.d(TAG + "--onNext  o=" + o);
            }

            @Override
            public void onError(Throwable e) {
                LogUtil.d(TAG + "--onError");
            }

            @Override
            public void onComplete() {
                LogUtil.d(TAG + "--onComplete");
            }
        };
        // 產生訂閱關係
        mObservable.subscribe(mObserver);
複製程式碼

再看看Rxjava強大的鏈式呼叫:

Observable.create(new ObservableOnSubscribe() {
       @Override
       public void subscribe(ObservableEmitter emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
                emitter.onComplete();
            }
            // 這裡直接通過subscribe將二者鏈式呼叫起來
        }).subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(Disposable d) {
                LogUtil.d(TAG + "--Observer--onSubscribe");
            }

            @Override
            public void onNext(Integer o) {
                LogUtil.d(TAG + "--Observer--onNext  o=" + o);
            }

            @Override
            public void onError(Throwable e) {
                LogUtil.d(TAG + "--Observer--onError");
            }

            @Override
            public void onComplete() {
                LogUtil.d(TAG + "--Observer--onComplete");
            }
        });
複製程式碼

我們前面說,RxJava是擴充於觀察者模式的響應式程式設計,所以在Rxjava中,就有觀察者被觀察者以及二者通過訂閱產生的依賴關係。

通過上面程式碼,可以看到:

被觀察者 ——————> Observable

觀察者 ——————> Observer

訂閱關係:Observable ————> subscribe <———— Observer

在上游的 Observable (被觀察者)中通過 emitter(發射器)就可以不斷地給下游的 Observer (觀察者)傳送資料流,我們在上游發射了 1、2、3還有發射了一個 onComplete 事件。

我們通過日誌可以看到,在下游的 Observer (觀察者)成功的接收到了上游傳送的數字1、2、3包括通過呼叫 onComplete()方法來接收上游傳送的 onComplete 事件。

通過上面一個簡單的例子,我們可以總結出以下幾點

4.1、解耦

我們可以看到被觀察者和觀察者都是獨立存在的。

Observable(被觀察者):

  // 通過 Observable 建立一個被觀察者
  Observable mObservable = Observable.create(new ObservableOnSubscribe() {
         @Override
         public void subscribe(ObservableEmitter emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
                emitter.onComplete();
            }
        });
複製程式碼

Observer(觀察者):

 // 通過Observer建立一個觀察者
        Observer mObserver = new Observer<Integer>() {
            @Override
            public void onSubscribe(Disposable d) {
                LogUtil.d(TAG + "--onSubscribe");
            }

            @Override
            public void onNext(Integer o) {
                LogUtil.d(TAG + "--onNext  o=" + o);
            }

            @Override
            public void onError(Throwable e) {
                LogUtil.d(TAG + "--onError");
            }

            @Override
            public void onComplete() {
                LogUtil.d(TAG + "--onComplete");
            }
        };
複製程式碼

可以看到,二者各自獨立存在,各幹各的事,只是通過 subscribe 來建立依賴關係,這樣的話,可以很好地實現程式碼的複用,比如我們可以建立多個Observer(觀察者),和Observable(被觀察者)之間通過訂閱建立依賴關係後,就能實現Observable(被觀察者)傳送的資料流被多個Observer(觀察者)接收。

4.2、資料流轉換(操作符的使用)

第二、Observable(被觀察者)通過 emitter(發射器)將資料以流的形式傳送給Observer(觀察者),前面講了,既然是以流的形式,那我們是不是可以在觀察者接收資料之前,對資料進行處理呢?答案是肯定的,這也是Rxjava的強大之一,它可以通過各種操作符來對資料進行處理,我們先講一個簡單的來。

這裡只是簡單的演示一些Rxjava對資料流的操作,後面會具體講操作符,圖片中可以看到,我們被觀察者明明發射的是一個int型的數值100,但是通過map操作符進行資料流進行轉換後,下游的消費者接收到的竟然是String的,這裡只是一個小Demo,在Rxjava中,還有各種很強大的操作符來對資料進行各種變態式的處理。

上游被觀察者Observable發射資料,下游除了使用Observer來接收資料外,還可以使用消費者Consumer來接收資料,可以看Consumer只有一個accept方法。

先貼一下Rxjava強大的操作符列表,是不是很多?不要被嚇到,越多所以我們可以越方便的對資料流進行各種各樣的操作,這個後面會單獨再講解。

4.3、執行緒切換

我們前面說了,Rxjava能更好的非同步操作,我們先用上面的例子列印一下他們當前所在的執行緒情況。

結果:

可以到,統一戰線的都在主執行緒,我們來看看,怎麼實現非同步。

同樣是那個例子,我們新增了下面這兩個程式碼

subscribeOn(Schedulers.io())
observeOn(AndroidSchedulers.mainThread())
複製程式碼

subscribeOn : 指定上游執行的執行緒

observeOn:指定觀察者或者消費者執行執行緒

結果:

程式碼中,我們指定上游在io執行緒,而下游在主執行緒執行,就這麼簡單的兩行程式碼,就實現了執行緒切換,實現了非同步操作,爽不爽?

當然,我們不光可以指定io執行緒,Schedulers還提供了其他的執行緒供我們選擇。

我們簡單看一個Single執行緒的原始碼:

是不是很熟悉?就是通過執行緒池來建立了一個單執行緒,其他類似,都是通過執行緒池來建立,您可以簡單去分析一下,當然,如果你對執行緒池還不熟悉的話,這篇 多執行緒(三)、執行緒池 ThreadPoolExecutor 知識點總結 可能適合你看看。

總結

Rxjava的東西還挺多的,這篇先簡單的走了一遍Rxjava的基礎概念還有簡單的使用,關於Rxjava裡面還有其他的觀察者模式的建立,背壓,各種操作符的使用、實戰等等騷操作,下篇繼續。

相關文章