rxjava2.+使用教程

前言

rxjava推出已經有相當長的一段時間了。本人作爲使用rxjava的菜鳥想對一些相關的使用做一些備註和總結。由於本人寫作能力有限,先推薦幾篇比較優秀的文件

  1. “給 Android 開發者的 RxJava 詳解”
    扔物線大神的。這個教程很不錯,不過這是rxjava1時期的文章。但文章的整個思路是非常不錯的。對rxjava的學習很有幫助,可以一讀。
  2. 這可能是最好的RxJava 2.x 教程
    這篇文章從 原理、使用、代碼、等多方面對rxjava2進行了系統的講解。

rxjava 到底是個什麼東西。扔物線大神說的很好,“異步”
rxjava的目的和 Handler、AsyncTask一樣都是爲了實現線程間的切換。但是他比 handler、asynctask這些都要靈活。

基本使用

  1. 創建Observable(被觀察者,用來發送消息)
  2. 創建Observer(創建觀察者,用來接收消息)
  3. 建立訂閱關係。這裏很多人會覺得奇怪,應用是觀察者訂閱被觀察者,但是代碼中卻是Observable.subscribe(Observer) 看起來像是被觀察者訂閱了觀察者。這是爲了保持代碼的鏈式結構。
//第一步: 創建 Observable(被觀察者)
Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                System.out.println("+++++++++++++++++++++++++++++" + 1);
                emitter.onNext(2);
                System.out.println("+++++++++++++++++++++++++++++" + 2);
                emitter.onNext(3);
                System.out.println("+++++++++++++++++++++++++++++" + 3);
                /* 這裏如果有異常的話,一定是發生在 onComplete 之前,不然異常無法被捕獲處理造成閃退 */
					//String a = null;
					//a.length();
					//String[] b = {"1"};
					//b[5].length();
                //如果 onError 之前沒有異常發生, 那麼 onError 之後的代碼將繼續執行,但是不會被觀察者捕獲
                emitter.onError(new Throwable("Throw an error !"));
                //當我們已經拋出了一個異常那麼第二個異常也無法被捕獲處理造成閃退
				//emitter.onError(new Throwable("Throw second error !"));
                System.out.println("+++++++++++++++++++++++++++++" + "onError");
                emitter.onComplete();
                System.out.println("+++++++++++++++++++++++++++++" + "onComplete");
                emitter.onNext(4);
                System.out.println("+++++++++++++++++++++++++++++" + 4);
            }
        })
        //第三步:建立訂閱關係
        .subscribe(new Observer<Integer>() {
        //第二步:創建observer(觀察者)
            @Override
            public void onSubscribe(Disposable d) {
                Log.i(TAG + "onSubscribe", d.isDisposed() + "");
            }
            @Override
            public void onNext(Integer integer) {
                Log.i(TAG + "onNext", integer + "");
                if (integer == 3) {
                    //切換操作,觀察者不再接受上游事件, 此後上游Observable將不能再拋出異常,否則異常無法被捕獲處理。
                    disposable.dispose();
                }
            }
            @Override
            public void onError(Throwable e) {
                Log.e(TAG + "onError", e.getMessage().toString());
            }
            @Override
            public void onComplete() {
                Log.e(TAG + "onComplete", "onComplete");
            }
        });

總結: 這裏是一些注意點有點繞,初學者可以暫且跳過

  1. 如果在消息源中有意外的異常拋出,那麼異常將被observer捕獲並在onError處理,並且中斷整條鏈式代碼的執行。如上代碼中 a.lenght() 執行後將在observer中的onError方法中捕獲 NullPointException 異常,並且這之後的代碼將不再執行。
  2. 消息源中 emitter.onErroremitter.onComplete()被調用後訂閱關係消息源中的代碼將繼續執行,但觀察者將不會對任何發出的消息進行處理。
    注意: 當訂閱關係取消後,消息源不能再以任何形式拋出異常,即使是emitter.onError這樣有意識的操作,因爲此時異常拋出後將不會被捕獲處理。

線程調度

先看代碼:

        observable
              //指定發射事件的線程爲 io 線程
              .subscribeOn(Schedulers.io())
              //指定接收者線程爲 Android主線程
              .observeOn(AndroidSchedulers.mainThread())
              .subscribe(observer1);

subscribeOn

此方法用於指定消息源發生的線程

observeOn

此方法用於指定消息處理的線程
注意:

  1. 多次指定消息源的線程只有第一次有效,subscribeOn只在第一次調用的時候有效
  2. 但是消息處理的線程可以多次切換,也就是說每調用一次observeOn消息處理的線程就切換一次
  3. RxJava 中,已經內置了很多線程選項供我們選擇,例如有:
  • Schdulers.io() 代表io操作的線程, 通常用於網絡,讀寫文件等io密集型的操作;
  • Schdulers.computation() 代表CPU計算密集型的操作, 例如需要大量計算的操作;
  • Schdulers.newThread() 代表一個常規的新線程;
  • AndroidSchdulers.mainThread() 代表Android的主線程;
    rxjava 內置的這些Scheduler 足夠滿足我們的需求,而且內部的線程調度採用線程池,效率也較高

Rxjava的靈活使用

通過以上我們簡單的瞭解了。rxjava的基本使用。但如果rxjava僅僅是這樣的話是不能滿足多樣的使用場景的,那也太弱了。下面我們來看看rxjava那些靈活的使用。

關於Observable和Observe的簡化創建

Observable的簡化創建

create() 方法是Rxjava中創建事件序列的最基本的方法。除此之外,rxjava還提供了一下快捷創建事件序列的方法

  • just(T...)
        /*
        just(T...)方法將依次發射 1,2,3,4等事件,相當於 執行 onNext(1), onNext(2), onNext(3) onNext(4);
        just方法最大的參數個數爲 10。
        */
        Observable.just(1, 2, 3, 4).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                //此處將依次收到 1,2,3,4等 4 個消息
                System.out.println("justjustjustjustjustjustjust------" + integer);
            }
        });
  • fromArray<T...items>
        /*
            fromArray<T...items> 方法的效果和just,fromIterable一樣,只是接收的參數是一個數組。
            當然,fromArray(1, 2, 3, 4) 像這樣調用也是一樣的。
            顯然的fromArray方法的參數個數是沒有限制的。
         */
        Integer[] strings1 = {1, 2, 3, 4};
        Observable.fromArray(strings1).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                System.out.println("fromArrayfromArrayfromArrayfromArray++++++++" + integer);
            }
        });
  • fromIterable<? extends T>
        List<String> stringList = new ArrayList<>();
        stringList.add("1");
        stringList.add("2");
        stringList.add("3");
        stringList.add("4");
        /*
            fromIterable<? extends T> 將依次發射 1,2,3,4,等4個事件,效果和上面just方法類似,
            但,很明顯的fromIterable方法將能承載更多的數據
         */
        Observable.fromIterable(stringList).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                System.out.println("fromfromfromfromfromfromfromfrom-------" + s);
            }
        });

Observe的簡化

如上例子中,如果我們不需要對 異常、完成 等信息進行處理,那麼直接訂閱一個consume作爲觀察者即可。
當然rxjava也提供了不同參數個數的subscribe()方法,可以根據需求設置捕獲 異常 或 完成 等消息

操作符

爲了方便使用,以及滿足各種使用場景,rxjava提供了衆多的方法,rxjava官方稱之爲“操作符”。當然上述Observable的各種創建方法也是操作符。下面我們來看一下常用的操作符。

轉換操作符

map

        Observable.just(1, 2, 3, 4)
                .map(new Function<Integer, String>() {
                    @Override
                    public String apply(Integer integer) throws Exception {
                    //將源消息中的integer 值轉換成我們需要的 String值
                        return "The value is " + integer;
                    }
                }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                System.out.println("------------" + s);
            }
        });

map是一個比較簡單的轉換操作符,通過規則將源消息中的 值,轉換成我們需要的值

flatmap

        Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9)
                .flatMap(new Function<Integer, ObservableSource<String>>() {
                    @Override
                    public ObservableSource<String> apply(Integer integer) throws Exception {
                        String a = integer + "";
                        return Observable.just(a).delay(10, TimeUnit.SECONDS);
                    }
                })
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        System.out.println("+++++++++++++++" + s);
                    }
                });

如上代碼,flatMap將integer類型的消息轉換成了String類型的消息。這裏要注意,flatMap是無序的
當然flatMap有很多其他變體,(如可以可以出來異常、完成時間的flatMap(Function onNextMapper, Function onErrorMapper, Callable))等等。這裏我只講最基本的。

groupBy

groupby將源Observable拆分成多個GroupedObservable,每個GroupedObservable發射一個Observable中的子序列。

        Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9)
                .groupBy(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(Integer integer) throws Exception {
                        //根據原始消息的不同,將源Observable拆分成不同的GroupedObservable。
                        // 並給下游消息隊列(即GroupedObservable)加上不同的 key 值
                        if (integer % 2 == 0) {
                            return 2;
                        } else {
                            return 1;
                        }
                    }
                }).subscribe(new Consumer<GroupedObservable<Integer, Integer>>() {
            @Override
            public void accept(GroupedObservable<Integer, Integer> integerIntegerGroupedObservable) throws Exception {
                //獲取消息隊列的 key之,採用 key 值來分辨消息隊列的種類
                int key = integerIntegerGroupedObservable.getKey();
                switch (key) {
                    case 1:
                        integerIntegerGroupedObservable
                                .subscribe(new Consumer<Integer>() {
                            @Override
                            public void accept(Integer integer) throws Exception {
                                System.out.println("---------------" + integer + " is a 奇數" );
                            }
                        });
                        break;
                    case 2:
                        integerIntegerGroupedObservable.subscribe(new Consumer<Integer>() {
                            @Override
                            public void accept(Integer integer) throws Exception {
                                System.out.println("+++++++++++++++" + integer + " is a 偶數" );
                            }
                        });
                        break;
                    default:
                        break;
                }
            }
        });

這裏有一個 groupby 的變種,groupBy(Function keySelector, Function valueSelector) 其中第二個參數是對消息的值進行的變換。

scan

        Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9)
                .scan(new BiFunction<Integer, Integer, Integer>() {
                    @Override
                    public Integer apply(Integer sum, Integer item) throws Exception {
                        //return值 將作爲下次調用此函數的第一個參數值
                        //注意:這裏會先將第一個消息發出給訂閱者來處理。
                        // 然後再將第一個消息的值作爲此函數的第一個參數,將第二個消息作爲第二個參數來第一次執行這個函數
                        return sum + item;
                    }
                }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                System.out.println("===========" + integer);
            }
        });

從代碼運行結果看出,scan使得訂閱者每次接收到的消息值都和上一次的消息值有關。*注意:*第一次的消息是不變的並會作爲apply方法第一次執行的第一個參數。當然我們也可以改變scan返回的消息的數據類型,這時候就要調用scan(final R initialValue, BiFunction accumulator)來設置觀察者接收到的第一個消息的初始值 initialValue;

window

window 操作符合buffer操作符類似。但buffer是將消息源轉換成一個個列表發射,而window是將消息源轉換成多個Observable,每個Observable發射一個子集。

        Observable.fromArray(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)
                .window(3)
                .subscribe(new Consumer<Observable<Integer>>() {
                    @Override
                    public void accept(Observable<Integer> integerObservable) throws Exception {
                        System.out.println("==================" + "第" + time + "組");
                        time ++;
                        integerObservable.subscribe(new Consumer<Integer>() {
                            @Override
                            public void accept(Integer integer) throws Exception {
                                System.out.println("----------" + integer);
                            }
                        });
                    }
                });
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章