目標場景:
熟悉Promise的朋友應該知道Promise中我們可以通過next進行鏈式調用。在調用的任何一個環節如果出現錯誤可以直接發射error信號終止鏈式調用。RxJava的onNext的發射邏輯和Promise有一些不同,并且一個訂閱事件不能再繼續執行后續的異步調用。在某一些場景下,我們希望能夠像Promise一樣通過一系列的鏈式異步調用完成一些系統功能的流程。例如,如果目前有N個任務,我們希望能夠對這N個任務進行順序執行,上一個任務如果正常執行,則繼續執行下一個任務,否則結束鏈式調用。
實現方案:
-
采用單個Flowable循環調用的方式。
Flowable.just(List<T> list)
.map(new Function<List<T>, O>(){
@Override
public O apply(List<T> list) throws Exception{
for (int m = 0; m < list.size(); m ++){
result = t.handle(); //偽方法示例
if (result!=SUCCESS){
throw new Exception(); //結束鏈式調用
}
}
return new O(); //返回一個結束消息
}
})
.subscribe(new Subscriber(){
...
@Override
void onNext(){
//這里處理返回結果
}
@Override
void onError(){
//這里處理錯誤
}
});
這種方案,怎么說呢,感覺和異步的結構不太一致,畢竟是采用循環的方式嵌套在一個map操作符里。
-
采用fromIterable
RxJava2 將RxJava1中的from拆解為若干個fromXXX操作符,對于容器,我們可以采用fromIterable。這個操作符是順序執行每次遍歷出來的內容,因此可以滿足鏈式調用的方法。
Flowable.fromIterable(List<T> list)
.map(new Function<T, O>(){
@Override
public O apply(T t){
result = t.handle(); //偽方法示例
if (result!=SUCCESS){
throw new Exception(); //結束鏈式調用
}
}
})
.subscribe(...);
這種方式比上一種在結構上更加清晰。我們也可以把map操作符替換成flatmap操作符去實現嵌套形式的鏈式調用。
但是,方案1和2有一個共同的問題,則是所有的任務必須在執行前全部寫入一個List。我們希望能夠更加靈活的添加鏈式任務,這時候我們可以直接使用連續的map操作符。
-
采用連續map
Flowable.just(T t)
//任務1
.map(new Function<T, T>(){
@Override
public T apply(T t){
result = t.handle(); //偽方法示例
if (result!=SUCCESS){
throw new Exception(); //結束鏈式調用
}
}
})
//任務2
.map(new Function<T, T>(){
@Override
public T apply(T t){
result = t.handle(); //偽方法示例
if (result!=SUCCESS){
throw new Exception(); //結束鏈式調用
}
}
})
...
.subscribe(...);
-
更復雜的場景
如果每個鏈式任務執行成功后要執行一些不同的額外操作,一個subsriber訂閱會有一些問題,RxJava2中提供了若干個doOnXXX操作符(doOnNext,doOnError,doOnComplete),原理上可以解決這個問題。如果采用fromIterable傳入鏈式任務,我們需要使用flatmap為每個調用單獨配置doOnXXX。
- 首先,把任務和額外的操作封裝成一個Bundle
interface RxTask{
int task(Object o);
}
class RxBundle{
RxTask task;
RxTask sideTask;
}
- 然后,把任務通過List方式傳入Flowable
Flowable.fromIterable(List<RxBundle> list)
.flatMap(new Function<RxBundle, Publisher<?>(){
@Override
public Publisher<?> apply(Bundle bundle){
final RxTask task = bundle.task;
final RxTask sideTask = bundle.sideTask
return Flowable.create(new FlowableOnSubscribe<Object>() {
@Override
public void subscribe(FlowableEmitter<Object> e) throws Exception {
int result = task.task();
if (result!=SUCCESS){
throw new Exception(); //結束鏈式調用
}
}
}, BackpressureStrategy.BUFFER))
.doOnNext(new Consumer(){
@Override
public void apply(Object o){
sideTask.task(); //這里執行額外操作
}
});
})
.subscribe(...);
這樣我們最終的回調結果是發射到.subscribe()當中,并且每一個調用都有針對的處理。
目前尚未驗證的是當某一個任務時扔出Exception整條鏈是否會停止執行。歡迎有經驗的同學補充。