将可观察对象发出的项转换为其他可观察对象是RX编程的重要部分。有几种种常见的转换操作符可以做到这一点,每种操作符都有不同的优点。在下面这个例子中,我将试图解释微妙的差异,并指出这些操作符的最佳用法。
直接上代码:
//变换操作符flatMap() switchMap() concatMap() concatMapEager()的区别以及开发中使用的注意点
//首先我们创建四个用于测试的调度器
final TestScheduler testScheduler1 = new TestScheduler();
final TestScheduler testScheduler2 = new TestScheduler();
final TestScheduler testScheduler3 = new TestScheduler();
final TestScheduler testScheduler4 = new TestScheduler();
String[] strArr = {"a","b","c","d"};
final int delay = 5000;
Observable.fromArray(strArr)
.flatMap(new Function<String, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(@NonNull String s) throws Exception {
return Observable.just(s+"---rxjava").delay(delay,TimeUnit.MILLISECONDS,testScheduler1).doOnNext(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.d(TAG, "timeflatMap1 :" + testScheduler1.now(TimeUnit.MILLISECONDS));
}
});
}
}).doOnNext(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.d(TAG, "accept: timeflatMap2 " + testScheduler1.now(TimeUnit.MILLISECONDS));
}
})
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.d(TAG, "accept: flatMap : " + s + " timeflatMap3 : " + testScheduler1.now(TimeUnit.MILLISECONDS));
}
});
//将调度程序的时钟按指定的时间向前移动10分钟看打印出来的数据
testScheduler1.advanceTimeBy(10,TimeUnit.MINUTES);
Observable.fromArray(strArr)
.concatMap(new Function<String, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(@NonNull String s) throws Exception {
return Observable.just(s+"---rxjava").delay(delay,TimeUnit.MILLISECONDS,testScheduler2).doOnNext(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.d(TAG, "timeconcatMap1 :" + testScheduler2.now(TimeUnit.MILLISECONDS));
}
});
}
}).doOnNext(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.d(TAG, "accept: timeconcatMap2 " + testScheduler2.now(TimeUnit.MILLISECONDS));
}
})
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.d(TAG, "accept: concatMap : " + s + " timeconcatMap3 : " + testScheduler2.now(TimeUnit.MILLISECONDS));
}
});
//将调度程序的时钟按指定的时间再向前累加移动10分钟看打印出来的数据
testScheduler2.advanceTimeBy(10,TimeUnit.MINUTES);
Observable.fromArray(strArr)
.concatMapEager(new Function<String, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(@NonNull String s) throws Exception {
return Observable.just(s+"---rxjava").delay(delay,TimeUnit.MILLISECONDS,testScheduler3).doOnNext(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.d(TAG, "timeconcatMapEager1 :" + testScheduler3.now(TimeUnit.MILLISECONDS));
}
});
}
}).doOnNext(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.d(TAG, "accept: timeconcatMapEager2 " + testScheduler3.now(TimeUnit.MILLISECONDS));
}
})
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.d(TAG, "accept: concatMapEager : " + s + " timeconcatMapEager3 : " + testScheduler3.now(TimeUnit.MILLISECONDS));
}
});
testScheduler3.advanceTimeBy(10,TimeUnit.MINUTES);
Observable.fromArray(strArr)
.switchMap(new Function<String, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(@NonNull String s) throws Exception {
return Observable.just(s+"---rxjava").delay(delay,TimeUnit.MILLISECONDS,testScheduler4).doOnNext(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.d(TAG, "timeswitchMap1 :" + testScheduler4.now(TimeUnit.MILLISECONDS));
}
});
}
}).doOnNext(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.d(TAG, "accept: timeswitchMap2 " + testScheduler4.now(TimeUnit.MILLISECONDS));
}
})
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
Log.d(TAG, "accept: switchMap : " + s + " timeswitchMap3 : " + testScheduler4.now(TimeUnit.MILLISECONDS));
}
});
testScheduler4.advanceTimeBy(10,TimeUnit.MINUTES);
打印结果:
通过以上结果我们可以得出:
flatMap():返回的item是无序的哪个item任务先完成就返回哪个item让下游进行处理 可以同时并行处理多个item的转换
concatMap():返回的item是有序的,其内部是严格按照上游Observable发射的数据item的顺序一个一个任务执行并返回
同时让下游进行响应处理的
switchMap():当上游Observable有新的数据item发射出来的时候会取消订阅之前的Observable通知订阅和监视最新的
这个Observable
concatMapEager()和concatMap()一样返回的item是有序的,其和concatMap()不一样的是concatMapEager()在执行任务
转换的时候是以并行处理所有的任务的但是并不是哪个转换任务先执行完就马上返回
结果让下游进行处理而是要缓存所有执行任务的结果然后严格按照上游Observable发射
数据item的顺序进行结果的发射来让下游进行处理
在开发中我们优先使用flatMap(), 如果对返回的数据的顺序有要求可以使用ConcatMap()但是要注意如果如果是比较重的多任务要考虑concatMap()是否合适而concatMapEager()在使用的时候则要考虑到内存的使用情况,因为其内部会缓存任务的返回结果(可能会oom)
本文章参考一下文章:
https://www.nurkiewicz.com/2017/08/flatmap-vs-concatmap-vs-concatmapeager.html