RxJava 2.0 使用詳解

使用

最基本的的使用

我們知道一個簡單的RxJava的應用,需要一個觀察者或者訂閱者Observer,一個被觀察者Observable,最後調用subscribe()方法將兩者綁定起來!
示例:

//創建觀察者或者訂閱者
Observer<String> observer = new Observer<String>() {
    @Override
    public void onSubscribe(Disposable d) {
    //Disposable是1.x的Subscription改名的,因爲Reactive-Streams規範用這個名稱,爲了避免重複
    //這個回調方法是在2.0之後新添加的
    //可以使用d.dispose()方法來取消訂閱
    }

    @Override
    public void onNext(String value) {
        Log.e("onNext", value);
    }

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

    @Override
    public void onComplete() {
        Log.e("onComplete", "complete");
    }
};

//創建被觀察者
Observable observable = Observable.create(new ObservableOnSubscribe() {
    @Override
    public void subscribe(ObservableEmitter e) throws Exception {
        e.onNext("Hello World!");
    }
});

observable.subscribe(observer);101112131415161718192021222324252627230332

這是一個非常簡單的例子,由於1.x中Observable不能合理的背壓,導致了無法意料的 MissingBackpressureException,所以在2.x中,添加了Flowable來支持背壓,而把Observable設計成非背壓的。
還有一點需要注意的就是,在上邊註釋中也有,onSubscribe(Disposable d)這個回調方法是在2.x中添加的,Dispose參數是由1.x中的Subscription改名的,爲了避免名稱衝突!
所以上邊的例子在2.x中,最好這麼寫:

//創建訂閱者
Subscriber<String> subscriber = new Subscriber<String>() {
    @Override
    public void onSubscribe(Subscription s) {
    //這一步是必須,我們通常可以在這裏做一些初始化操作,調用request()方法表示初始化工作已經完成
    //調用request()方法,會立即觸發onNext()方法
    //在onComplete()方法完成,纔會再執行request()後邊的代碼
    s.request(Long.MAX_VALUE);
    }

    @Override
    public void onNext(String value) {
        Log.e("onNext", value);
    }

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

    @Override
    public void onComplete() {
    //由於Reactive-Streams的兼容性,方法onCompleted被重命名爲onComplete
        Log.e("onComplete", "complete");
    }
};

Flowable.create(new FlowableOnSubscribe<String>() {
    @Override
    public void subscribe(FlowableEmitter<String> e) throws Exception {
        e.onNext("Hello,I am China!");
    }
}, BackpressureStrategy.BUFFER)
    .subscribe(subscriber);     

在2.x中,我們在onSubscribe()回調中必須調用s.request()方法去請求資源,參數就是要請求的數量,一般如果不限制請求數量,可以寫成Long.MAX_VALUE,之後會立即觸發onNext()方法!所以當你在onSubscribe()/onStart()中做了一些初始化的工作,而這些工作是在request()後面時,會出現一些問題,在onNext()執行時,你的初始化工作的那部分代碼還沒有執行。爲了避免這種情況,請確保你調用request()時,已經把所有初始化工作做完了。

更簡潔的寫法

Flowable.just("Hello,I am China!")
    .subscribe(subscriber);
    //.subscribeWith(subscriber)//在1.x中此方法返回Subscription,而在2.x中是沒有返回值的
    //所以增加subscribeWith()方法,用來返回一個Disposable對象
    //使得用戶可以CompositeDisposable.add()方法添加對象。1.x爲CompositeSubscription
    //其他subscribe()重載方法返回Disposable

RxJava提供了just()方法來創建一個發射字符串的Flowable,然後調用subcribe()即可!
這裏還有一個需要注意的問題,就是在註釋中寫的subcribe()方法有多種重載方法,只有subscribe(subscriber)這個重載方法時沒有返回值的,但是在1.x中,此方法返回Subscription(上邊也提到過,在2.x中改名爲Disposable),用戶經常添加SubscriptionCompositeSubscription(2.x中改名爲CompositeDisposable),爲了彌補這一點,我們增加了E subscribeWith(E subscriber)方法,返回一個Disposable對象,使得用戶可以CompositeDisposable.add()方法添加對象。

而對於 Subscriber 來說,我們目前僅僅關心onNext方法。所以又可以這樣寫:

Flowable.just("Hello,I am China!")
    //替代1.x中的action1,接收一個參數,如果是兩個參數action2使用BiCustomer,而且刪除了action3-9
    //多個參數用Custom<Object[]>
    .subscribe(new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            Log.e("consumer", s);
        }
    });

需要注意的問題:在1.x的API中,這裏是Action1,在2.x中使用Consumer來代替,如果是兩個參數,則用BiConsumer來代替Action2,而且在2.x中刪除了Action3-9,如果是多個參數則用Custom<Object[]>代替ActionN。

RxJava還有一個API能達到類似的效果,就是from(),但是因爲在使用java8編譯時,javac不能夠區分功能接口類型,所以它在2.x中被拆分爲:fromArray,fromIterable,fromFuture
所以上邊又可以這樣寫:

Flowable.fromArray("Hello,I am China!")
    .subscribe(new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            Log.e("consumer", s);
        }
        });

操作符

map

首先看一個map的例子

Flowable.just("Hello,I am China!")
    //將1.x中的Func1,2改爲Function和BiFunction,Func3-9改爲Function3-9
    //多參數FuncN改爲Function<Object[],R>

    //這個第一個泛型爲接收參數的數據類型,第二個泛型爲轉換後要發射的數據類型
    .map(new Function<String, String>() {
        @Override
        public String apply(String s) throws Exception {
            return s+"__by Mars";
        }
    })
    .subscribe(new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            Log.e("consumer", s);
        }
    });*/

可以看出,例子中map()將一個字符串對象,轉換爲另一個字符串對象返回,當然我們也可以將其轉換爲與之不同的對象,對應的返回的Flowable對象參數也會變爲轉換後的對象。另外Function的泛型第一個爲接收參數的數據類型,第二個爲轉換後要發射的數據類型。
需要注意的問題:在2.x中將1.x的Func1Func2改爲FunctionBiFunctionFunc3-9改爲Function3-9,多參數FuncN改爲Function<Object[],R>

map()的邏輯操作圖:
這裏寫圖片描述

flatMap

首先看一個例子:

ArrayList<String[]> list=new ArrayList<>();
String[] words1={"Hello,","I am","China!"};
String[] words2={"Hello,","I am","Beijing!"};
list.add(words1);
list.add(words2);
Flowable.fromIterable(list)
    .flatMap(new Function<String[], Publisher<String>>() {
        @Override
        public Publisher<String> apply(String[] strings) throws Exception {
            return Flowable.fromArray(strings);
        }
    })
    .subscribe(new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            Log.e("consumer", s);
        }
    });

從上邊這個例子可以看出,flatMap和map還是有共同點的,都是將一個對象轉換爲另一個對象,不同的是map只是一對一的轉換,而flatMap可以是一對多的轉換,並且是轉換爲另外一個Flowable對象!

flatMap()的邏輯操作圖:
這裏寫圖片描述

lift和compose

關於這些轉換的使用和原理,可以參考扔物線的
給 Android 開發者的 RxJava 詳解
2.x中的用法基本相同

concat和merge

concat

邏輯操作圖:
這裏寫圖片描述

merge

邏輯操作圖:
這裏寫圖片描述

上述所有邏輯操作圖來自這裏

其他api

Flowable.range(5,10)//從5開始數10個數(5——14)
    .filter(new Predicate<Integer>() {//過濾爲偶數
        @Override
        public boolean test(Integer integer) throws Exception {
            return integer%2==0;
        }
    })
    .take(2)//只要前2個數據
    .subscribe(new Consumer<Integer>() {
        @Override
        public void accept(Integer integer) throws Exception {
            Log.e("consumer", integer+"");
        }
    });

上邊註釋已經寫的很清楚了!
range()方法,第一個參數爲開始值,第二個參數爲數量,所以別搞錯了,以爲第二個參數爲結束值;filter()方法用於對數據進行過濾;take(n)方法用於取前n個值。

在Android中的使用

RxJava在Android中的使用,主要就體現在異步這一點。對應RxJava,RxAndroid也已經到2.x版本。
我在上一篇博客中也提到過,涉及兩個比較核心的方法subscribeOn和observeOn這兩個方法都傳入一個Scheduler對象,subscribeOn指定發射事件的線程,observeOn指定消費事件的線程。
在2.x的API中仍然支持主要的默認scheduler: computation, io, newThreadtrampoline,可以通過io.reactivex.schedulers.Schedulers這個實用的工具類來調度。

我們在android中主要就使用下邊這兩個就夠了:
Schedulers.io(): I/O 操作(讀寫文件、讀寫數據庫、網絡信息交互等)所使用的 Scheduler。行爲模式和 newThread() 差不多,區別在於 io() 的內部實現是是用一個無數量上限的線程池,可以重用空閒的線程,因此多數情況下 io() 比 newThread() 更有效率。不要把計算工作放在 io() 中,可以避免創建不必要的線程。
AndroidSchedulers.mainThread(),它指定的操作將在 Android 主線程運行。

這裏一個最簡單的例子:

Flowable.just("Hello,I am China!")
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(subscriber)

所以在Android中創建Flowable時,即發射數據源的時候的耗時操作,可以指定在io()線程中,得到數據後,更新UI可以指定在mainThread()中。

當然現在最經典的就是RxAndroid和Retrofit的結合使用了:
這裏有一個比較牛逼的寫法總結:
RxJava 與 Retrofit 結合的最佳實踐
這篇文章是基於1.x寫的,不過在2.x中用法大同小異。
另外需要注意的問題就是,retrofit現在還未支持RxJava2.x,不過不用擔心,jake大神已經給我們寫好了適配器:

compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

在gradle中添加依賴即可!
然後在創建Retrofit對象時,這樣寫:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//1.X爲RxJavaCallAdapterFactory
    .build();

就可以在Retrofit2中盡情使用RxJava2了!

好了,先這樣吧,上邊就是RxJava涉及到的比較基礎的東西!

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