RxJava2中如何按依赖关系串行执行列表内的Single任务
问题场景
需要串行执行一组返回相同MyObject类型的RxJava Single任务,且每个任务需要接收上一个任务的输出作为入参。硬编码连续调用flatMap的方式,在任务数量动态变化、或任务以集合形式存储时维护成本很高,而原生concat操作符不支持上下游结果传递,无法满足带依赖传参的串行执行需求。
原有代码示例如下:
// 省略getter/setter public class MyObject { private String a; private String b; private String c; // ...其他字段 } public Single<MyObject> methodA (MyObject o) { return Single.fromCallable(() -> { MyObject result; if (Objects.nonNull(o)) { result = (MyObject) o.clone(); } else { result = new MyObject(); } result.setA("a"); return result; }); } // methodB、methodC逻辑和methodA类似,分别给对象的b、c字段赋值
原有硬编码串联写法:
Single<MyObject> result = Single.just(new MyObject()) .flatMap(x -> methodA(x)) .flatMap(x -> methodB(x));
实现方案
首先需要纠正一个认知误区:不要尝试直接用List<Single<MyObject>>实现这个需求。Single在创建时就已经捕获了它需要的入参,没有入口动态传入上一步的执行结果,你需要存储的是Function<MyObject, SingleSource<MyObject>>类型的任务函数——也就是接收上一步结果、返回对应Single任务的方法引用(比如this::methodA、this::methodB都属于这个类型),才能实现动态传参的串行执行。
方案1:封装通用工具方法(最直观、性能最好)
直接抽一个通用的链式拼接工具,循环组装flatMap调用,逻辑简单无额外依赖:
public class RxChainUtil { /** * 串行执行带参数传递的Single任务链 * @param initial 初始入参对象 * @param tasks 任务函数列表,每个函数接收上一步结果,返回新的Single任务 * @return 串联完成后的最终Single结果 * @param <T> 任务处理的对象类型 */ public static <T> Single<T> chainSingle(T initial, List<Function<T, SingleSource<T>>> tasks) { Single<T> current = Single.just(initial); for (Function<T, SingleSource<T>> task : tasks) { current = current.flatMap(task); } return current; } }
调用方式非常简洁,后续新增任务只需要往列表里加元素即可,不需要修改链式调用代码:
// 组装任务列表 List<Function<MyObject, SingleSource<MyObject>>> taskList = Arrays.asList( this::methodA, this::methodB, this::methodC ); // 直接执行拿到最终结果 Single<MyObject> result = RxChainUtil.chainSingle(new MyObject(), taskList);
方案2:用reduce操作符函数式串联
如果不想写循环,也可以用流的reduce操作符动态拼接flatMap链,完全非阻塞:
List<Function<MyObject, SingleSource<MyObject>>> taskList = Arrays.asList( this::methodA, this::methodB, this::methodC ); Single<MyObject> result = Single.just(new MyObject()) .flatMapPublisher(initialObj -> Flowable.fromIterable(taskList) .reduce( Single.just(initialObj), (prevSingle, task) -> prevSingle.flatMap(task) ) .toFlowable() ) .singleOrError() .flatMap(s -> s);
内容的提问来源于stack exchange,提问作者chavalife17
相关产品推荐
相关产品推荐

