RxJava基礎使用

RxJava是什么

RxJava is a Java VM implementation of Reactive Extensions: a library for composing asynchronous and event-based programs by using observable sequences.這是官方對于該庫的描述,意思是RxJava是Java VM上一個靈活的,使用可觀測序列組成的異步的、基于事件的庫。 它的核心最主要在于它的“異步”, Observable(被觀察者)與 Observer/Subscriber(觀察者),Observable可發出一系列事件,事件執行完畢后回調被觀察者,這里的事件可以有非常多種形式,例如:網絡請求、文件操作、數據加載、循環、延時操作等等。

相關概念

同步/異步: 關注的是消息通信機制,同步是指 發出一個調用,在沒有得到結果之前,該調用就不返回,但是一旦調用返回,就得到返回值了; 而異步是指 調用發出后,調用直接返回,但不會立刻得到調用的結果。而是在調用發出后,被調用者通過狀態、通知來通知調用者,或通過回調函數處理這個調用; 異步強調被動通知。

阻塞/非阻塞:關注的是程序在等待調用結果(消息,返回值)時的狀態;阻塞調用是指調用結果返回之前,當前線程會被掛起。調用線程只有在得到結果之后才會返回。 非阻塞調用指在不能立刻得到結果之前,該調用不會阻塞當前線程。如java8 stream為阻塞式,Future為非阻塞式的; 非阻塞強調狀態主動輪詢。

并發(Concurrency)與并行(parallelism): 并發是一個更通用的概念,兩個并發線程被調度在一個單核處理上運行,這就是并發性,而非并行. 并行性更可能出現在多核,多CPU或分布式系統上。編寫代碼時一般不區分兩者。

函數式編程Functional Programming):函數式編程將程序描述為表達式和變換,以數學方程的形式建立模型,并盡量避免可變的狀態。每個邏輯分類(filter,map,reduce等)都由不同函數所表示,這些實現底層次的變換,而用戶定義的高階函數作為參數來實現真正的業務。

函數響應式編程(Functional Reactive Programming)):響應式編程是建立在觀者者模式上的一種編程范式,對異步數據流進行編程,同時該事件流是按時間排序的序列(不同于java8中的stream);雖然響應式編程框架不一定要求是函數式的,但是RxJava等響應式編程框架都是結合了函數式編程的。

背壓(Backpressure):背壓是指在異步場景中,被觀察者發送事件速度遠快于觀察者的處理速度的情況下,一種告訴上游的被觀察者降低發送速度的策略,簡而言之,背壓是流速控制的一種策略。

ReactiveX是什么

響應式擴展(Reactive Extensions, 簡寫為ReactiveX,Rx),最初是LINQ的一個擴展,由微軟的架構師Erik Meijer領導的團隊開發,在2012年11月開源[1];

ReactiveX = Observer Pattern + Iterator Pattern + Functional Programming。Rx 讓開發者可以利用可觀察序列和LINQ風格查詢操作符來編寫異步和基于事件的程序;

ReactiveX是一個編程模型,目標是提供一致的編程接口,幫助開發者更方便的處理異步數據流,ReactiveX的思想是跨平臺的,學習其他語言的基本語法之后,可以做到 “learn once, write everywhere”;

Rx近幾年越來越流行了,現在已經支持幾乎全部的流行編程語言了,Rx的大部分語言庫由ReactiveX這個組織負責維護,比較流行的有RxJava/RxJS/Rx.NET,社區網站是 reactivex.io。

RxJava 是 ReactiveX 規范的JVM平臺實現

組織結構

RxJava核心由以下四個interface定義:

Publisher : 消息發布者
Subscriber : 消息訂閱者
Subscription : 一個訂閱
Processor : Publisher + Subscriber 的結合體

它有什么作用

1.使你的代碼更加簡潔,增強可讀性
2.對事件的處理具有非常好的靈活性
3.非常方便的實現響應式編程
4.對線程與并發問題的處理變得簡單
5.Flow Control(Backpressure、Throttling等)

基本使用

引入RxJava依賴,這里使用的2.x版本

repositories {
    maven { url 'https://oss.jfrog.org/libs-snapshot' }
}

dependencies {
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
}

最簡單的開始

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                e.onNext("hello");
                e.onNext("rxjava");
                e.onNext("test");
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {

            }

            @Override
            public void onNext(@NonNull String s) {
                System.out.println("MainActivity.onNext:" + s);
            }

            @Override
            public void onError(@NonNull Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });

Observable創建一個基于String類型的事件,然后被觀察者調用subscribe方法訂閱觀察者。What?是不是搞反了。
ObservableEmitter為事件發射器,可調用onNext、onError、onComplete方法,Disposable用于解除訂閱。
事件的執行內容是:依次輸出“hello”,“rxjava”,“test”三個字符串。這里使用的方法鏈的方式,當然你也可以采用以下的方式

這里寫圖片描述

create方法是Observable的靜態方法,用于構造一個Observable對象,如果說用于單純的構造初始事件的話,除了create以外,還有許多方式可以構造觀察者

interval & intervalRange & just & fromIterable & fromArray & timer

他們與create的差異主要在于,create創建的事件需要執行過程,而這些方法創建的事件顯示是現成的,不需要額外操作,一旦與觀察者關聯后即可發送事件。

fromFuture & fromCallable 了解即可,Android中并不太適用

fromFuture, 事件從非主線程中產生; fromCallable, 事件從主線程中產生, 在需要消費時生產;

        ExecutorService executor = Executors.newFixedThreadPool(2);
        Callable<String> callable = new Callable<String>() {...};
        Future<String> future = executor.submit(callable);
        Consumer<String> onNext = new Consumer<String>() {...};
        Flowable.fromCallable(callable).subscribe(onNext);
        Flowable.fromFuture(future).subscribe(onNext);

ObservableEmitter和Disposable

ObservableEmitter: ObservableEmitter可以理解為發射器,這個就是用來發出事件的,它可以發出三種類型的事件,通過調用emitter的onNext(T value)、onComplete()和onError(Throwable error)就可以分別發出next事件、complete事件和error事件。

1.被觀察者可以發送無限個onNext, 觀察者也可以接收無限個onNext.
2.當Observable發送了一個onComplete后, Observable的onComplete之后的事件將會繼續發送, 而Observer收到onComplete事件之后將不再繼續接收事件.
3.當Observable發送了一個onError后, Observable中onError之后的事件將繼續發送, 而Observer收到onError事件之后將不再繼續接收事件.
4.Observable可以不發送onComplete或onError.
5.最為關鍵的是onComplete和onError必須唯一并且互斥, 即不能發多個onComplete, 也不能發多個onError, 也不能先發一個onComplete, 然后再發一個onError, 反之亦然。

Disposable 調用dispose()方法時, 它就會將觀察者和被觀察者的聯系切斷, 從而導致觀察者收不到事件。但是并不能控制被觀察者是否發射事件。

Observale & Flowable

當然我們也可以使用Flowable,而不用Observale

Flowable.create(new FlowableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull FlowableEmitter<String> e) throws Exception {
                e.onNext("hello");
                e.onNext("rxjava");
                e.onNext("test");
            }
        }, BackpressureStrategy.BUFFER).subscribe();

Observable: 不支持背壓
Flowable : Observable新的實現,支持背壓,同時實現Reactive Streams 的 Publisher 接口

其他形式的被觀察者

除了上述描述的兩種觀察者形式外,還有Single & Completable & Maybe

Single

可以發射一個單獨onSuccess 或 onError消息。它現在按照Reactive-Streams規范被重新設計,并遵循協議 onSubscribe (onSuccess | onError)

Single.create(new SingleOnSubscribe<Object>() {...)
        .subscribe(new SingleObserver<Object>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onSuccess(Object value) {

            }

            @Override
            public void onError(Throwable e) {

            }
        });

Completable

可以發送一個單獨的成功或異常的信號,按照Reactive-Streams規范被重新設計,并遵循協議onSubscribe (onComplete | onError)

Completable.create(new CompletableOnSubscribe() {
            @Override
            public void subscribe(CompletableEmitter e) throws Exception {

            }
        }).subscribe(new Action() {
            @Override
            public void run() throws Exception {
                // complete
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                // error
            }
        });

Completable

它是Single 和 Completable 的結合體。它可以發射0個或1個通知或錯誤的信號, 遵循協議 onSubscribe (onSuccess | onError | onComplete)

Maybe.create(new MaybeOnSubscribe<Object>() {
            @Override
            public void subscribe(MaybeEmitter<Object> e) throws Exception {

            }
        }).subscribe(new Consumer<Object>() {
            @Override
            public void accept(Object o) throws Exception {
                // success
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                // error
            }
        }, new Action() {
            @Override
            public void run() throws Exception {
                // complete
            }
        });

簡化訂閱

觀察者除了用Observer對象外,我們還可以用Consumer單獨接收onNext或者onError以及onSubscribe回調,用Action單獨接收onComplete,下圖是訂閱關聯的各個重載方法subscribe的參數列表

這里寫圖片描述

什么時候用 Observable
一般處理最大不超過1000條數據,并且幾乎不會出現內存溢出
如果處理的式同步流而你的Java平臺又不支持Java Stream

什么時候用 Flowable
處理以某種方式產生超過10K的元素
有很多的阻塞和/或 基于拉取的數據源,但是又想得到一個響應式非阻塞接口的

線程調度

默認情況下, Observer和Observable是工作在同一個線程中的, 也就是說Observable在哪個線程工作,就在哪個線程發送事件, Observer也就在同樣的線程中接收處理事件

  • subscribeOn() 指定的就是發射事件的線程,observerOn 指定的就是訂閱者接收事件的線程
  • 多次指定發射事件的線程只有第一次指定的有效,也就是說多次調用 subscribeOn() 只有第一次的有效
  • 允許多次指定訂閱者接收線程,每調observerOn,下游都會進行線程切換

RxJava內置線程選項:

  • Schedulers.io() 代表io操作的線程, 通常用于網絡,讀寫文件等io密集型的操作;
  • Schedulers.computation() 代表CPU計算密集型的操作, 例如需要大量計算的操作;
  • Schedulers.newThread() 代表一個常規的新線程;
  • AndroidSchedulers.mainThread() 代表Android的主線程

操作符

RxJava是基于事件序列、異步的操作庫,它提供了許多操作符,這些操作符可以在整體事件序列中對元素或者事件本身進行一系列變換,下面為大家介紹一些常用的操作符的使用

concat

將多個Observable按順序發射數據,不會交錯,只有前一個 Observable 終止(onComplete) 后才會訂閱下一個 Observable

        Observable observable1 = Observable.fromArray(1,2,3);
        Observable observable2 = Observable.fromArray(4,5,6);
        Observable.concat(observable1, observable2).subscribe(new Consumer() {
            @Override
            public void accept(Object o) throws Exception {
                System.out.println("MainActivity.accept" + o);
            }
        });
這里寫圖片描述

merge

將多個Observable數據合并,各個數據順序可能交錯

Observable observable1 = Observable.intervalRange(1, 10, 1, 1, TimeUnit.SECONDS);
        Observable observable2 = Observable.intervalRange(1, 3, 2, 2, TimeUnit.SECONDS);
        Observable.merge(observable1, observable2).subscribeOn(Schedulers.io()).subscribe(new Consumer() {
            @Override
            public void accept(Object o) throws Exception {
                System.out.println("MainActivity.accept" + o);
            }
        });
這里寫圖片描述

map

將一個Observable發射的數據根據某種映射關系轉換為另一個形式的數據

Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
                e.onNext(R.mipmap.ic_launcher);
            }
        }).map(new Function<Integer, Drawable>() {
            @Override
            public Drawable apply(@NonNull Integer integer) throws Exception {
                return getResources().getDrawable(integer);
            }
        }).subscribe(new Consumer<Drawable>() {
            @Override
            public void accept(Drawable drawable) throws Exception {
                img.setImageDrawable(drawable);
            }
        });

flatMap

flatMap 操作符可以將一個發射數據的 Observable 變換為多個 Observables ,然后將它們發射的數據合并后放到一個單獨的 Observable,并且事件有可能交錯

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                e.onNext("a");
                e.onNext("b");
                e.onNext("c");
            }
        }).flatMap(new Function<String, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(@NonNull String s) throws Exception {
                List<String> list = new ArrayList();
                list.add(s);
                list.add(s);
                list.add(s);
                return Observable.fromIterable(list).delay(1,TimeUnit.SECONDS);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.e(TAG,s);
            }
        });
這里寫圖片描述

concatMap

作用等同于flatMap,唯一不同的是concatMap事件序列嚴格按照上流的發送順序

zip

將多個Observable的事件壓縮到一起再發送

Observable name = Observable.fromArray("lee","su","liu");
        Observable age = Observable.fromArray(22,31,18);
        Observable.zip(name, age, new BiFunction<String,Integer,User>() {
            @Override
            public User apply(@NonNull String o, @NonNull Integer o2) throws Exception {
                return new User(o,o2);
            }
        }).subscribe(new Consumer<User>() {
            @Override
            public void accept(User o) throws Exception {

            }
        });

filter

對上流發射的數據進行篩選,過濾到不符合條件的數據

Observable.fromArray(1,2,3,4,5,6).filter(new Predicate<Integer>() {
            @Override
            public boolean test(@NonNull Integer integer) throws Exception {
                return integer%2 == 0;
            }
        }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e(TAG,"過濾得到的整數" + integer);
            }
        });
這里寫圖片描述

take

事件數量限制,保留指定數量內的事件

Observable.fromArray(1,2,3,4,5,6).take(3).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e(TAG,"value : " + integer);
            }
        });
這里寫圖片描述

doOnNext

在回調觀察者onNext方法前進行額外的處理

Observable.fromArray(1,2,3,4,5,6).take(3)
                .doOnNext(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.e(TAG,"doOnNext : " + integer);
                    }
                })
                .subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e(TAG,"value : " + integer);
            }
        });
這里寫圖片描述

debounce

用于事件的過濾,其官方解釋是數據的發射都延時指定時間后進行,并且在這段延時內新數據將會把老數據替換掉,在每次執行e.onNext(value)后計時器重置。簡單說,就是在指定時間內,只接收時間段內的最新數據。

Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onNext(3);
            }
        }).debounce(10, TimeUnit.MILLISECONDS, Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.e(TAG,"value : " + integer);
                    }
                });
這里寫圖片描述

throttleFirst

用于事件的過濾,在指定時間間隔內只保留第一個事件

Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                for(int i=0;i<10;i++){
                    e.onNext(i);
                    SystemClock.sleep(1500);
                }
            }
        }).throttleFirst(2000, TimeUnit.MILLISECONDS, Schedulers.io())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.e(TAG,"value : " + integer);
                    }
                });
這里寫圖片描述

compose

與 flatMap 類似,都是進行變換,但是compose操作與返回的都是Observable對象,并且激活并發送事件。compose操作符擁有更高層次的抽象概念:它操作于整個數據流中,不僅僅是某一個被發送的事件。
1.compose 是唯一一個能夠從數據流中得到原始Observable的操作符,所以,那些需要對整個數據流產生作用的操作(比如,subscribeOn()和observeOn())需要使用 compose 來實現。相較而言,如果在flatMap()中使用subscribeOn()或者observeOn(),那么它僅僅對在flatMap 中創建的Observable起作用,而不會對剩下的流產生影響。這樣就可以簡化subscribeOn()以及observeOn()的調用次數了。
2.compose 是對 Observable 整體的變換,換句話說, flatMap 轉換Observable里的每一個事件,而 compose 轉換的是整個Observable數據流。

First

同樣用于事件過濾,只發送所有事件中的第一個事件

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("a");
                e.onNext("b");
                e.onNext("c");
            }
        }).first(null).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.e(TAG,"first value is "+s);
            }
        });
這里寫圖片描述

distinct & distinctUntilChanged

distinct( )過濾掉重復數據;distinctUntilChanged()過濾掉連續重復的數據。

Observable.just(1,2,1,1,3,4,5).distinct().subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e(TAG,"distinct "+integer);
            }
        });
        Observable.just(1,2,1,1,3,4,5).distinctUntilChanged().subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e(TAG,"distinctUntilChanged "+integer);
            }
        });
這里寫圖片描述

總結

這篇文章帶大家了解什么是RxJava,以及涉及到的相關概念。并且整理了RxJava的基本用法,以及常用的操作符的作用與使用方式。RxJava中的操作符非常多,這里只是列舉了部分常用操作符講解,更多的可以參考以下文檔

RxJava Wiki:https://github.com/ReactiveX/RxJava/wiki
RxJava 中文文檔:https://mcxiaoke.gitbooks.io/rxdocs/content/

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容