如何用RxJava、RxKotlin和Retrofit的flatMap实现API顺序调用?
可行方案:用RxJava/RxKotlin + Retrofit的flatMap串联顺序API调用
当然有完美的解决方案!你想要的正是RxJava中flatMap操作符的核心场景——它就是用来把多个Observable(或Flowable)串联起来,让前一个的输出直接作为后一个的输入,完全不需要为每个API写独立的订阅逻辑。结合Retrofit的Rx支持,整个流程会非常简洁。
下面我一步步给你拆解实现思路和代码示例:
1. 先定义Retrofit的API接口
首先要确保你的Retrofit接口方法返回RxJava类型(比如Observable或Flowable),而不是传统的Call:
interface ApiService { // API1: 接收Spinner选中的参数,返回Observable<Api1Response> @GET("api/endpoint1") fun callApi1(@Query("selectedOption") option: String): Observable<Api1Response> // API2: 接收API1的输出作为参数,返回Observable<Api2Response> @POST("api/endpoint2") fun callApi2(@Body request: Api1Response): Observable<Api2Response> // API3: 接收API2的输出作为参数,返回Observable<Api3Response> @POST("api/endpoint3") fun callApi3(@Body request: Api2Response): Observable<Api3Response> }
2. 把Spinner的选中事件转换成Observable
要触发整个流程,我们需要把Spinner的选择事件包装成Observable。这里有两种实现方式:
方式一:用RxBinding(推荐,简化View事件转换)
// 先添加RxBinding依赖,直接把Spinner的选中事件转成Observable val spinnerSelectionObservable = RxSpinner.itemSelections(spinner) .map { it.toString() } // 把选中的Item转换成API1需要的参数格式
方式二:手动实现(无需额外依赖)
val spinnerSelectionObservable = Observable.create<String> { emitter -> spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { val selectedOption = parent?.getItemAtPosition(position).toString() emitter.onNext(selectedOption) } override fun onNothingSelected(parent: AdapterView<*>?) { // 可选:处理未选中的情况 } } // 销毁时取消监听,避免内存泄漏 emitter.setCancellable { spinner.onItemSelectedListener = null } }
3. 用flatMap串联三个API调用
这一步是核心!通过flatMap把三个API的Observable串联起来,每一步的输出自动作为下一步的输入:
// 初始化ApiService实例(假设你已经配置好Retrofit) val apiService = Retrofit.Builder() .baseUrl("https://your-base-url.com/") .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) // 必须添加Rx的CallAdapter .build() .create(ApiService::class.java) // 串联整个调用流程 spinnerSelectionObservable .distinctUntilChanged() // 避免重复选中同一选项时重复触发请求 .flatMap { selectedOption -> // 第一步:调用API1,传入Spinner选中的参数 apiService.callApi1(selectedOption) } .flatMap { api1Response -> // 第二步:用API1的输出调用API2 apiService.callApi2(api1Response) } .flatMap { api2Response -> // 第三步:用API2的输出调用API3 apiService.callApi3(api2Response) } .subscribeOn(Schedulers.io()) // 网络请求在IO线程执行 .observeOn(AndroidSchedulers.mainThread()) // 结果回调回到主线程更新UI .subscribe( // 最终成功回调:API3执行完成后的处理 { api3Response -> Toast.makeText(context, "API3调用成功:${api3Response.data}", Toast.LENGTH_SHORT).show() // 这里可以添加UI更新逻辑 }, // 错误回调:任何一步出错都会触发这里 { error -> Log.e("ApiFlow", "流程出错:${error.message}", error) Toast.makeText(context, "请求失败:${error.message}", Toast.LENGTH_SHORT).show() } )
关键说明
flatMap的核心作用:它会订阅前一个Observable的输出,然后返回一个新的Observable(即下一个API的请求),天然实现了顺序依赖的调用逻辑。- 线程管理:
subscribeOn(Schedulers.io())确保网络请求在后台线程执行,observeOn(AndroidSchedulers.mainThread())让结果回到主线程,避免ANR。 - 统一错误处理:整个流程中任何一个API调用失败,都会直接触发错误回调,不用为每个API单独写异常处理。
- 防重复请求:
distinctUntilChanged()可以过滤掉重复的选中事件,避免不必要的重复调用。
这样一来,你就不需要为每个API写独立的Observer和订阅代码了,整个流程是链式的,逻辑清晰且易于维护。
内容的提问来源于stack exchange,提问作者IID
相关产品推荐
相关产品推荐

