Rxjava的使用_1

         最近工作用Rxjava,發現有些東西忘記了,翻了翻資料,纔想起來。可能是年紀大了記性不好,所以在這裏寫下來,以後在需要查資料就不用去到處找了,直接看自己的博客就好了。

依賴

在安卓中,除了依賴RxJava外,還需要依賴一下RxAndroid

compile 'io.reactivex.rxjava2:rxandroid:2.1.0'
compile 'io.reactivex.rxjava2:rxjava:2.1.0'

鑑於RxJava源碼比較多,本系列不會分析源碼,主要介紹一些常用到的東西

1. RxJava簡要介紹

RxJava中有三個關鍵點
Observable,被觀察者
Observer,觀察者
subscribe,建立訂閱關係

在觀察者模式中,一般都是觀察者訂閱被觀察者
但在RxJava中,是Observable.subscribe(Observer)

被觀察者有變化,觀察者就會知道。

 

有一個類比水管的說法,水管說:

RxJava事件流向.png

Observable,上游水管
Observer,下游水管
subscribe,連接上下游的水管

水管接上之後,上游水管裏的水流動,下流水管裏的水就會流動。

2. 基本使用

廢話不多說,先來一段代碼感受一下

 //關注點1
    Observable<String> observable=Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> emitter) throws Exception {
            Log.d("TAG","subscribe");
            emitter.onNext("1");
            emitter.onNext("2");
            emitter.onNext("3");
            emitter.onComplete();
        }
    });

    //關注點2
    Observer<String> observer=new Observer<String>() {
        @Override
        public void onSubscribe(Disposable d) {
            Log.d("TAG","onSubscribe");

        }

        @Override
        public void onNext(String s) {
            Log.d("TAG",s);
        }

        @Override
        public void onError(Throwable e) {
            Log.d("TAG","onError");
        }

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

    //關注點3
    observable.subscribe(observer);

這段代碼的執行結果

D/TAG: onSubscribe
D/TAG: subscribe
D/TAG: 1
D/TAG: 2
D/TAG: 3
D/TAG: onComplete

站在水管的角度
把關注點1比喻成一根水管,處在上游
把關注點2也比喻成一根水管,處在下游
關注點3就是連接這兩根水管的一個媒介,通過該媒介關注點1和關注點2就連通了。

我們在來看看剩下的兩個比較陌生的類
ObservableEmitter和Disposable
ObservableEmitter
這是一個接口,繼承自Emitter接口,翻譯過來就是發射器的意思,而它就是用來發出事件的,通過調用emitter的onNext(T value),
onError(Throwable t)和onComplete()分別用來發生next事件,error事件和complete事件。

下面來總結一下事件的發送接收規則

  • 事件是發送一個,接收一個,然後才發送下一個。
  • 上游可以發送無限個next事件,下游也可以接收無限個next事件。
  • 當上遊發送complete或者error事件後,下游不會在接收complete或者error事件之後的事件,但上游會將全部事件都發送完。
  • 上游的complete和error事件必須唯一且互斥,否則可能相應的事件不會被下游接收到,並且可能會發生手機崩潰的情況。

Disposable(這一點不是最常用的一部分,瞭解一下就好了)
Disposable是一個接口,裏面就兩個方法

 void dispose();
 boolean isDisposed();

修改關注點1和關注點2的代碼

  //關注點1
    Observable<String> observable=Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> emitter) throws Exception {
            Log.d("TAG","subscribe");
            emitter.onNext("1");
            emitter.onNext("2");
            emitter.onComplete();
            emitter.onNext("3");
            Log.d("TAG","emitter 3");
        }
    });

    //關注點2
    Observer<String> observer=new Observer<String>() {
        Disposable disposable;
        @Override
        public void onSubscribe(Disposable d) {
            Log.d("TAG","onSubscribe");
            disposable=d;

        }

        @Override
        public void onNext(String s) {
            Log.d("TAG",s);
            if(s.equals("1")){
                disposable.dispose();
                Log.d("TAG", "isDisposed : " + disposable.isDisposed());
            }
        }

        @Override
        public void onError(Throwable e) {
            Log.d("TAG","onError:"+e.getMessage());
        }

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

輸出結果

D/TAG: onSubscribe
D/TAG: subscribe
D/TAG: 1
D/TAG: isDisposed : true
D/TAG: emitter 3

結果分析
當在下游調用disposable.dispose()方法時,下游將不會在接收後續的事件,但上游還是會將全部事件發送完畢。
這裏的dispose就相當於將水管切斷了,因此接收不了後續事件。

鏈式調用(上面講了那麼多,其實最重要的事這一部分,我們常用的就是這一部分。)
我們來稍微修改一下之前的寫法,就變成了RxJava流行的鏈式調用寫法了。

 Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> emitter) throws Exception {

        }
    }).subscribe(new Observer<String>() {
        @Override
        public void onSubscribe(Disposable d) {
            
        }

        @Override
        public void onNext(String s) {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onComplete() {

        }
    });

上面的寫法就是常用的鏈式寫法,但是還有一點小問題,就是默認被觀察者觀察者都是在主線程中運行的,如果我們用它來做耗時操作,就要放在子線程中,操作完成之後又要轉到主線程去更新UI,這樣又要用handler,線程切換比較麻煩。其實Rxjava已經爲我們處理了。

observable有兩個方法分別指定被觀察者觀察者代碼運行 線程。

observable.subscribeOn(Schedulers.io());//指定被觀察者運行在子線程。(上游水管)
observable.observeOn(AndroidSchedulers.mainThread());//指定觀察者運行在主線程。(下游水管)

RxJava已經爲我們提供了一下幾個Scheduler

  • Schedulers.immediate():直接在當前線程運行,相當於不指定線程。這是默認的 Scheduler。
  • Schedulers.newThread():總是啓用新線程,並在新線程執行操作。
  • Schedulers.io(): I/O 操作(讀寫文件、讀寫數據庫、網絡信息交互等)所使用的 Scheduler。行爲模式和 newThread() 差不多,區別在於 io() 的內部實現是是用一個無數量上限的線程池,可以重用空閒的線程,因此多數情況下 io() 比 newThread() 更有效率。不要把計算工作放在 io() 中,可以避免創建不必要的線程。
  • Schedulers.computation():計算所使用的 Scheduler。這個計算指的是 CPU 密集型計算,即不會被 I/O 等操作限制性能的操作,例如圖形的計算。這個 Scheduler 使用的固定的線程池,大小爲 CPU 核數。不要把 I/O 操作放在 computation() 中,否則 I/O 操作的等待時間會浪費 CPU。
  • AndroidSchedulers.mainThread():它指定的操作將在 Android 主線程運行。

可以根據自己的需要去選擇被觀察者和觀察者所在的線程。

鏈式編程

 Observable.create(new ObservableOnSubscribe<Object>() {
                    @Override
                    public void subscribe(ObservableEmitter<Object> e) throws Exception {
                        Log.i("ceshi", "subscribe " + Thread.currentThread().getName());
                        e.onNext("好好學習,天天向上");
                    }
                }).subscribeOn(Schedulers.io())//指定被觀察者運行的線程。
                        .observeOn(AndroidSchedulers.mainThread())//指定觀察者運行的線程。
                        .subscribe(new Observer<Object>() {
                            @Override
                            public void onSubscribe(Disposable d) {
                                Log.i("ceshi", "onSubscribe d = " + d + Thread.currentThread().getName());
                            }

                            @Override
                            public void onNext(Object value) {
                                Log.i("ceshi", "onNext value = " + value + "  " + Thread.currentThread().getName());

                            }

                            @Override
                            public void onError(Throwable e) {
                                Log.i("ceshi", "onError e = " + e.toString() + "  " + Thread.currentThread().getName());
                            }

                            @Override
                            public void onComplete() {
                                Log.i("ceshi", "onComplete  ");
                            }
                        });

運行的結果

11-29 10:50:58.272 23384-23384/com.airbridge.rxjavademo I/ceshi: onSubscribe d = 0main
11-29 10:50:58.274 23384-23523/com.airbridge.rxjavademo I/ceshi: subscribe RxCachedThreadScheduler-1
11-29 10:50:58.278 23384-23384/com.airbridge.rxjavademo I/ceshi: onNext value = 好好學習,天天向上  main
11-29 10:50:58.278 23384-23384/com.airbridge.rxjavademo I/ceshi: onComplete  

這就是我們常用的鏈式編程方式,下一篇我們來講一下背壓問題。下一篇講背壓的博客:Rxjava的使用_2(背壓問題)

如果需要上面的源碼,可以去下載 RxjavaDemo.zip

本篇中有一部分截圖和代碼是從這個https://www.jianshu.com/p/9561ebdc5c0b哥們兒博客裏面借用的。大家也可以去看的博客。

 

發佈了15 篇原創文章 · 獲贊 1 · 訪問量 6638
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章