根据this thread conCatMap和flatmap仅根据项目的发布顺序而不同。所以我做了一个测试并创建了一个简单的整数流,并希望看到它们将以什么顺序发出。我制作了一个小的可观察量,它将在1-5的范围内取数,并将它们乘以2。简单。
以下是包含flatmap的代码:
myObservable.flatMap(new Func1<Integer, Observable<Integer>>() {
@Override
public Observable<Integer> call(Integer integer) {
return Observable.just(integer * 2);
}
}).subscribe(new Observer<Integer>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer integer) {
Log.v("myapp","from flatMap:"+integer);
}
});
和使用concatMap完全相同的代码:
myObservable.concatMap(new Func1<Integer, Observable<Integer>>() {
@Override
public Observable<Integer> call(Integer integer) {
return Observable.just(integer * 2);
}
}).subscribe(new Observer<Integer>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer integer) {
Log.v("myapp","from concatmap:"+integer);
}
});
当我在日志中看到打印时,两者的排序是相同的,为什么?我以为只有concatMap会保留顺序吗?
答案 0 :(得分:9)
你所看到的是巧合。每次flatMap
返回一个值时,它都会在与前一个相同的线程上完成。
我修改了你的例子以利用多线程:
Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.flatMap(integer -> Observable.just(integer)
.observeOn(Schedulers.computation())
.flatMap(i -> {
try {
Thread.sleep(new Random().nextInt(1000));
return Observable.just(2 * i);
} catch (InterruptedException e) {
e.printStackTrace();
return Observable.error(e);
}
}))
.subscribe(System.out::println,
Throwable::printStackTrace,
() -> System.out.println("onCompleted"));
我将每个2 * i
值延迟一个随机延迟以强制执行不同的顺序。另外,我在此之前添加了observeOn(Schedulers.computation())
,因此下一个运算符(flatMap
)在计算线程池上运行 - 这就是多线程魔术。
这是我的示例(在Android上)获得的输出:
I/System.out: 6
I/System.out: 4
I/System.out: 12
I/System.out: 14
I/System.out: 8
I/System.out: 2
I/System.out: 16
I/System.out: 20
I/System.out: 10
I/System.out: 18
I/System.out: onCompleted
如果我在flatMap
之后用just
替换concatMap
,那么我会得到一个正确排序的输出。
有一个great post by Thomas Nield有正确的解释。