如何使用RxJava实现多请求依次执行并传递前序结果?
这是一个典型的顺序依赖型异步请求场景,RxJava的flatMap操作符就是为这种需求量身打造的——它能完美串联起多个需要前序结果作为参数的Observable,避免嵌套回调的地狱。下面是标准且简洁的实现方案:
1. 补全必要依赖
首先确保你的build.gradle里包含Retrofit与RxJava配合的核心依赖(你给出的初始依赖缺了关键的RxJava适配器):
// Retrofit核心库 implementation 'com.squareup.retrofit2:retrofit:2.3.0' // Retrofit的RxJava2适配器(让接口返回Observable类型) implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' // RxJava2核心库 implementation 'io.reactivex.rxjava2:rxjava:2.2.20' // JSON解析转换器(根据接口返回格式调整,这里用Gson示例) implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
2. 定义Retrofit API接口
根据三个请求的依赖关系,定义对应的接口方法,每个方法返回Observable,并接收前序请求的结果作为参数:
public interface BookyApi { // Step1: 获取用户信息,无参数 @GET("step1user") Observable<User> getStep1User(); // Step2: 用Step1返回的用户ID作为参数获取Cookie @GET("step2cookie") Observable<Cookie> getStep2Cookie(@Query("userId") String userId); // Step3: 用Step2返回的Cookie值作为参数获取Token @GET("step3token") Observable<Token> getStep3Token(@Query("cookie") String cookieValue); }
同时根据接口返回的JSON结构定义对应的实体类(示例简化版):
// Step1返回的用户实体 public class User { private String userId; public String getUserId() { return userId; } } // Step2返回的Cookie实体 public class Cookie { private String cookieValue; public String getCookieValue() { return cookieValue; } } // Step3返回的Token实体 public class Token { private String token; public String getToken() { return token; } }
3. 核心RxJava链式调用
用flatMap串联三个请求,实现顺序执行与参数传递,同时做好线程调度和订阅管理:
// 1. 创建Retrofit实例 Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://jimclermonts.nl/booky/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); BookyApi bookyApi = retrofit.create(BookyApi.class); // 2. 执行链式请求 Disposable disposable = bookyApi.getStep1User() // 指定网络请求在IO线程执行 .subscribeOn(Schedulers.io()) // 第一个flatMap:用Step1的用户结果发起Step2请求 .flatMap(user -> bookyApi.getStep2Cookie(user.getUserId())) // 第二个flatMap:用Step2的Cookie结果发起Step3请求 .flatMap(cookie -> bookyApi.getStep3Token(cookie.getCookieValue())) // 指定回调在主线程执行(Android场景下用于更新UI) .observeOn(AndroidSchedulers.mainThread()) // 订阅结果 .subscribe( // 最终成功回调:拿到第三步的Token token -> { Log.d("BookyDemo", "最终获取到Token: " + token.getToken()); // 这里处理最终业务逻辑 }, // 错误回调:任何一步请求失败都会触发这里 throwable -> { Log.e("BookyDemo", "请求失败: ", throwable); // 统一处理错误(比如弹窗提示、重试) } ); // 3. 记得在合适时机(如页面销毁)取消订阅,避免内存泄漏 // disposable.dispose();
为什么选择flatMap?
flatMap的核心作用是将一个Observable发射的元素转换成另一个Observable,并自动订阅新的Observable,把它的结果传递给下游。相比嵌套订阅(比如在Step1的回调里再发起Step2请求),flatMap能让代码保持线性结构,可读性更强,也更便于统一处理错误和线程调度。
额外注意事项
- 错误处理:整个链式调用中任何环节出错,都会直接走到错误回调。如果需要针对不同步骤做差异化错误恢复,可以使用
onErrorResumeNext、retry等操作符。 - 线程调度:
subscribeOn仅需调用一次,会作用于整个上游的Observable;observeOn可以多次调用,用于切换不同的回调线程。 - 订阅管理:Android场景下建议用
CompositeDisposable统一管理多个Disposable,在页面销毁时批量取消订阅,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Jim Clermonts
相关产品推荐
相关产品推荐

