RxJava - flatmap vs concatMap - 为什么在订阅时订购相同?

时间:2016-03-21 13:11:39

标签: rx-java flatmap concatmap

根据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会保留顺序吗?

1 个答案:

答案 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有正确的解释。