使用
最基本的的使用
我們知道一個簡單的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),用戶經常添加Subscription
到CompositeSubscription
(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的Func1
和Func2
改爲Function
和BiFunction
,Func3-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
, newThread
和
trampoline
,可以通過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涉及到的比較基礎的東西!