前言
第一次接觸學習RxJava應該是一兩個月前的事情了,但其中也是斷斷續續,最近又再次去學習RxJava,和當初剛接觸RxJava完全不是同樣的心情,輕鬆了很多,也感受到了RxJava的魅力,真是不由衷感嘆太牛了。目前關於RxJava的文章也很多,個人推薦兩篇扔物線的給 Android 開發者的 RxJava 詳解和大頭鬼Bruce的譯文 深入淺出RxJava系列。那麼這篇文章通過程式碼介紹RxJava中的操作符,以及操作符的使用。當然操作符較多,準備分幾篇文章介紹。如果你想提前學習其他操作符可以去GitHub,歡迎star專案。
RxJava操作符原始碼傳送門
基礎介紹
為了力求有沒有RxJava基礎都能看懂此文,簡單介紹一下RxJava以及一些名詞。在RxJava開源的Github上是這樣解釋的a library for composing asynchronous and event-based programs using observable sequences for the Java VM。無論多麼複雜的邏輯,都可以保持整潔的程式碼格式。
在RxJava中最重要的就是Observable(被觀察者),subscribe(訂閱),Observer(觀察者)或者Subscriber(訂閱者),Observable也就是資料(事件)源,Subscriber負責接收以及處理資料(事件)。當然要想實現兩者通訊,需要有一種機制那就是訂閱。Observer 通過 subscribe() 方法實現訂閱關係,從而 Observable 可以在需要的時候發出事件來通知 Observer。
例如張三(觀察者)想看某款新聞軟體的科技資訊(被觀察者),由於科技資訊是每天推送或者不定時推送,如果張三一直盯著手機螢幕看並且重新整理訊息是不是又新的資訊,顯然不現實。這時候就可以通過張三 subscribe(訂閱)科技資訊,而實現當有新的科技資訊時自動給張三推送訊息,在這期間,張三並不需要一直盯著螢幕重新整理聞。在RxJava程式碼書寫時應該是張三.subscribe(科技新聞)。
在RxJava中,有三個事件回撥方法,分別是onNext(),OnError(),onCompleted(),onNext()是最終輸出及處理資料的回撥,在發射資料過程中出現錯誤異常會回撥OnError()方法,當不會再有新的 onNext() 發出時,需要觸發 onCompleted() 方法作為標誌。,OnError()和onCompleted()是互斥的。下面舉一個最簡單的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Observable observable2 = Observable.just("也許當初忙著微笑和哭泣", "忙著追逐天空中的流星", "人理所當然的忘記", "是誰風裡雨裡一直默默守護在原地"); Subscriber subscriber = new Subscriber() { @Override public void onCompleted() { Log.e(TAG, "onCompleted: " ) } @Override public void onError(Throwable e) { Log.e(TAG, "onError: ") } @Override public void onNext(String s) { Log.e(TAG, "onNext: "+s ) } }; observable.subscribe(subscriber); |
執行後列印資訊為
1 2 3 4 5 |
onNext: 也許當初忙著微笑和哭泣 onNext: 忙著追逐天空中的流星 onNext: 人理所當然的忘記 onNext: 是誰風裡雨裡一直默默守護在原地 onCompleted: |
Create
我們可以使用該操作符從零開始建立一個Observable,給這個操作符傳遞一個接受觀察者作為引數的函式,並呼叫觀察者的onNext,onError和onCompleted方法。如下
1 2 3 4 5 6 7 8 9 10 11 |
//被觀察者 Observable observable = Observable.create(new Observable.OnSubscribe() { @Override public void call(Subscriber super String> subscriber) { //可以多次呼叫subscriber.onNext("大家好")發射資料 subscriber.onNext("大家好"); subscriber.onNext("我開始學習RxJava"); subscriber.onCompleted(); } }); |
傳送資料需要在毀掉方法call中呼叫subscriber的onNext(),onNext(T)傳送的引數需要和Observable.OnSubscribe()中引數相同,在上面我們傳入的是String型別。建立後Observale後,我們需要建立Subscriber(觀察者)去處理observable傳送的資料。如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Subscriber subscriber = new Subscriber() { @Override public void onCompleted() { Log.e(TAG, "onCompleted"); } @Override public void onError(Throwable e) { Log.e(TAG, e.getMessage()); } @Override public void onNext(String s) { Log.e(TAG, "onNext:"+s); } }; |
資料成功傳送後,會回撥Subscriber的onNext()的方法,其中的引數就是接收到的資料。當onNext()接收資料完畢後會執行onCompleted(),如果中途有環節出現錯誤異常,會執行onError()。現在觀察者和被觀察者都建立完畢了,他們執行還需要一個前提就是訂閱,如果不訂閱,observable並不會發射資料,subscribe也不會接收資料,訂閱程式碼如下
1 |
observable.subscribe(subscriber); |
執行後輸出資訊
1 2 3 |
onNext:大家好 onNext:我開始學習RxJava onCompleted |
from
該操作符是將其它種類的物件和資料型別轉換為Observable,如果當你發射的的資料是同一種型別,而不是混合使用Observables和其它型別的資料,會非常方便。如下建立Observable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Integer[] integers = {1,2, 3, 4}; Observable observable=Observable.from(integers); Subscriber subscriber = new Subscriber() { @Override public void onCompleted() { Log.e(TAG, "onCompleted"); } @Override public void onError(Throwable e) { Log.e(TAG, e.getMessage()); } @Override public void onNext(Integer i) { Log.e(TAG, "onNext:"+i); } }; observable.subscribe(subscriber); |
輸出資訊為
1 2 3 4 5 |
onNext:1 onNext:2 onNext:3 onNext:4 onCompleted |
from操作符可以轉換Future、Iterable和陣列。對於Iterable和陣列,產生的Observable會發射Iterable或陣列的每一項資料。對於Future,它會發射Future.get()方法返回的單個資料,並且還可以增加通過: from(Future,timeout, timeUnit)指定超時時間,如果執行的時候Future超時會回撥onError()方法。
just
just將單個資料轉換為發射那個資料的Observable,Just類似於From,但是From會將陣列或Iterable的資料取出然後逐個發射,而Just只是簡單的原樣發射,將陣列或Iterable當做單個資料,如果你傳遞null給Just,它會返回一個發射null值的Observable。不要誤認為它會返回一個空Observable(完全不發射任何資料的Observable)。對於just可以接收1到10個資料,返回一個按引數列表順序發射這些資料的Observable。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Observable.just(1 2, 3, 4) .subscribe(new SubscriberInteger>() { @Override public void onCompleted() { Log.e(TAG, "onCompleted: "); } @Override public void onError(Throwable e) { Log.e(TAG, "onError: "); } @Override public void onNext(Integer integer) { Log.e(TAG, "onNext: " + integer); } }); |
輸出
1 2 3 4 5 |
onNext:1 onNext:2 onNext:3 onNext:4 onCompleted: |
對於just引數型別可以是多種,如下,傳入兩個型別資料
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Observable.just(0, "one", 6, "two", 8, "three") .subscribe(new Subscriber() { @Override public void onCompleted() { Log.e(TAG, "onCompleted: " ); } @Override public void onError(Throwable e) { Log.e(TAG, "onError: "); } @Override public void onNext(Serializable serializable) { Log.e(TAG, "onNext: "+serializable.toString()); } }); |
則輸出資訊
1 2 3 4 5 6 7 |
onNext:0 onNext:one onNext:6 onNext:two onNext:8 onNext:three onCompleted: |
Empty/Never/Error
Empty:建立一個不發射任何資料但是正常終止的Observable,此時會回撥onCompleted()
Never:建立一個不發射資料也不終止的Observable
Error:建立一個不發射資料以一個錯誤終止的Observable
error操作符需要一個Throwable引數,你的Observable會以此終止。這些操作符預設不在任何特定的排程器上執行,但是empty和error有一個可選引數是Scheduler,如果你傳遞了Scheduler引數,它們會在你指定的排程器上傳送通知。
Range
該操作符建立特定整數序列的Observable,它接受兩個引數,一個是範圍的起始值,一個是範圍的資料的數目。如果你將第二個引數設為0,將導致Observable不發射任何資料(如果設定為負數,會拋異常)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Observable.range(1,4) .subscribe(new SubscriberInteger>() { public String TAG="RXJAVA"; @Override public void onCompleted() { Log.e(TAG, "onCompleted: " ); } @Override public void onError(Throwable e) { Log.e(TAG, "onError: "); } @Override public void onNext(Integer integer) { Log.e(TAG, "onNext: "+integer); } }); |
輸出資訊
1 2 3 4 5 |
onNext: 1 onNext: 2 onNext: 3 onNext: 4 onCompleted: |
你可以在程式碼實戰中,更改第二個引數為負數,或者0,以及將第一個引數更改為你想測試的任意值,去觀察執行日誌幫助理解。
Timer
Timer操作符建立一個在給定的時間段之後返回一個特殊值的Observable。它在延遲一段給定的時間後發射一個簡單的數字0 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Observable.timer(1, TimeUnit.SECONDS) .subscribe(new Subscriber() { public String TAG="RXJAVA"; @Override public void onCompleted() { Log.e(TAG, "onCompleted: " ); } @Override public void onError(Throwable e) { Log.e(TAG, "onError: "); } @Override public void onNext(Long integer) { Log.e(TAG, "onNext:1111111 "+integer); } }); |
對於該操作符預設在computation排程器上執行的,如果你想在onNext()回撥方法更新UI,需要通過observeOn(AndroidSchedulers.mainThread())設定,否則會呼叫onError()方法。當然Time人提供的有一個三個引數的方法timer(long,TimeUnit,Scheduler)可以指定 Scheduler 。
Interval
該操作符按固定的時間間隔發射一個無限遞增的整數序列,它接受一個表示時間間隔的引數和一個表示時間單位的引數,當然該操作符合Timer一樣,是在computation排程器上執行的,若想更新UI需要指定Scheduler 為AndroidSchedulers.mainThread()。
1 2 3 4 5 6 7 8 |
Subscription subscription = Observable.interval(1, TimeUnit.SECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1() { @Override public void call(Long aLong) { tv.append(" " + aLong + " "); } }); |
通過上面程式碼就會每隔1秒在tv上追加一個數字,並且會永遠執行。如果在某個時刻不想繼續輸出,就需要要解除訂閱。
1 2 3 |
if (subscription != null && !subscription.isUnsubscribed()) { subscription.unsubscribe(); } |
Repeat
該操作符是重複的發射某個資料序列,並且可以自己設定重複的次數。當接收到onComplete()會觸發重訂閱再次重複發射資料,當重複發射資料次數到達後執行onCompleted()。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
String[] strs = {"也許當初忙著微笑和哭泣", "忙著追逐天空中的流星"}; Observable.from(strs).repeat(2)..subscribe(new Subscriber() { @Override public void onCompleted() { Log.e(TAG, "onCompleted: " ); } @Override public void onError(Throwable e) { Log.e(TAG, "onError: "); } @Override public void onNext(String s) { Log.e(TAG, "onNext: "+s ); tv1.append("\n" + s); } }); |
輸出
1 2 3 4 5 |
onNext: 也許當初忙著微笑和哭泣 onNext: 忙著追逐天空中的流星 onNext: 也許當初忙著微笑和哭泣 onNext: 忙著追逐天空中的流星 onCompleted: |
Defer
直到有觀察者訂閱時才建立Observable,並且為每個觀察者建立一個新的Observable,該操作符能保證訂閱執行時資料來源是最新的資料。如下正常程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
String test="舊資料"; Observable observable=Observable.just(test); Subscriber subscriber=new Subscriber() { public String TAG="RXJAVA"; @Override public void onCompleted() { Log.e(TAG, "onCompleted: " ); } @Override public void onError(Throwable e) { Log.e(TAG, "onError: " ); } @Override public void onNext(Object o) { Log.e(TAG, "onNext: "+o ); } }; test="新資料"; observable.subscribe(subscriber); |
輸出
1 2 |
onNext: 舊資料 onCompleted: |
通過上面程式碼和輸出日誌發現,雖然在後面講資料test更新為新資料,但是並沒有生效,要想使用最新的資料就需要使用defer操作符。此時更改使用defer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
test="舊資料"; Observable observable=Observable.defer(new Func0>() { @Override public Observablecall() { return Observable.just(test); } }); Subscriber subscriber=new Subscriber() { public String TAG="RXJAVA"; @Override public void onCompleted() { Log.e(TAG, "onCompleted: " ); } @Override public void onError(Throwable e) { Log.e(TAG, "onError: " ); } @Override public void onNext(Object o) { Log.e(TAG, "onNext: "+o ); } }; test="新資料"; observable.subscribe(subscriber); |
輸出資訊
1 2 |
onNext: 新資料 onCompleted: |
通過新的列印資訊,發現輸出值已經是最新的資料。
到這裡,這篇文章暫時就先結束了,若文章有不足或者錯誤的地方,歡迎指正,以防止給其他讀者錯誤引導。更多的操作符,將在接下來的幾篇文章介紹。
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式