RxJava 2.0 使用詳解
前言
在上一篇部落格中,提到了RxJava的一些比較核心的東西,還有與1.x版本的一些區別!
現在我們具體瞭解一下它的使用!
使用
最基本的的使用
我們知道一個簡單的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);
- 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
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 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
- 28
- 29
- 30
- 31
- 32
- 33
- 34
這是一個非常簡單的例子,由於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);
- 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
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 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
- 28
- 29
- 30
- 31
- 32
- 33
- 34
在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
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
需要注意的問題:在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);
}
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
操作符
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);
}
});*/
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
可以看出,例子中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);
}
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
從上邊這個例子可以看出,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+"");
}
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
上邊註釋已經寫的很清楚了!
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)
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
所以在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'
- 1
- 1
在gradle中新增依賴即可!
然後在建立Retrofit物件時,這樣寫:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//1.X為RxJavaCallAdapterFactory
.build();
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
就可以在Retrofit2中盡情使用RxJava2了!
好了,先這樣吧,上邊就是RxJava涉及到的比較基礎的東西!
相關文章
- 詳解Android RxJava的使用AndroidRxJava
- Retrofit2.0使用詳解
- OAuth 2.0詳解OAuth
- 給 Android 開發者的 RxJava 詳解AndroidRxJava
- Android Retrofit 2.0(二)使用教程OkHttp3 + Gson + RxJavaAndroidHTTPRxJava
- 關於 RxJava 最友好的文章—— RxJava 2.0 全新來襲RxJava
- RxJava2.0 及Retrofit2.0學習資源RxJava
- RxJava2 錯誤處理詳解RxJava
- RxJava2.0——變換操作符RxJava
- 淺談RxJava與2.0的新特性RxJava
- Android RxJava :圖文詳解 背壓策略AndroidRxJava
- OAuth 2.0授權框架詳解OAuth框架
- 給初學者的RxJava2.0教程(三)RxJava
- 給初學者的RxJava2.0教程(七)RxJava
- 給初學者的 RxJava2.0 教程 (四)RxJava
- 給初學者的RxJava2.0教程(一)RxJava
- 給初學者的RxJava2.0教程(二)RxJava
- 給初學者的RxJava2.0教程(五)RxJava
- 給初學者的 RxJava2.0 教程 (八)RxJava
- 給初學者的RxJava2.0教程(四)RxJava
- 給初學者的RxJava2.0教程(八)RxJava
- 給初學者的RxJava2.0教程(九)RxJava
- 給初學者的 RxJava2.0 教程 (九)RxJava
- SpringBoot admin 2.0 詳解Spring Boot
- Spring Boot Admin 2.0 詳解Spring Boot
- OAuth 2.0 授權認證詳解OAuth
- oauth2.0密碼模式詳解OAuth密碼模式
- NUnit2.0詳細使用方法
- 詳解 RxJava2 的執行緒切換原理RxJava執行緒
- OAuth2.0授權碼模式詳解OAuth模式
- 史上最全的Rxjava2講解(使用篇)RxJava
- Android RxJava應用例項講解:你該什麼時候使用RxJava?AndroidRxJava
- 扔物線大佬的給 Android 開發者的 RxJava 詳解AndroidRxJava
- Android中RxJava+Retrofit2.0+MVP模式的整合AndroidRxJavaMVP模式
- Milvus 2.0 質量保障系統詳解
- webpack(2.0)入門詳解 | 掘金技術徵文Web
- RxJava使用總結RxJava
- 實戰Spring Boot 2.0系列(三) – 使用@Async進行非同步呼叫詳解Spring Boot非同步