You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Rx:如何非阻塞处理多API请求队列?

Rx+Retrofit 实现失败POST请求缓存重发的最优方案

核心思路

要实现「单个请求失败不阻塞队列」+「失败请求缓存重发」,核心是让每个请求的错误被独立隔离处理,不让单个请求的异常扩散到整个队列流中。同时需要一套可靠的缓存机制存储失败请求的完整上下文,后续按需触发重发。

比递归更优的实现方案

递归方案容易陷入嵌套逻辑,且难以控制并发和队列状态,推荐以下几种Rx原生操作符组合的方案:

1. 用 concatMapEager 处理有序请求队列

如果需要保证请求的执行顺序,concatMapEager 是比普通 concatMap 更高效的选择:它会同时订阅所有请求Observable,但严格按原始顺序发射结果。每个请求的错误可以在内部捕获,不会中断整个队列。

  • 每个请求的错误逻辑单独处理:失败时存入缓存,成功时移除缓存项
  • 用 onErrorResumeNext(Observable.empty()) 让单个请求失败后,队列继续处理下一个请求

2. 结合 BehaviorSubject 实现可动态触发的任务流

用 BehaviorSubject 作为队列的「触发器」,不管是首次发起请求,还是后续重发缓存的请求,都可以通过向Subject发送信号来触发执行。这种方式可以灵活控制队列的启停、新增任务:

  • 当有新请求需要执行时,将请求对象发送到Subject
  • 订阅Subject的流,用 flatMap 或 concatMapEager 处理每个请求
  • 失败请求存入缓存,待网络恢复或手动触发时,将缓存的请求重新发送到Subject

3. 用 Completable.mergeDelayError 批量并行重发

如果不需要严格的执行顺序,批量重发缓存请求时可以用 mergeDelayError:它会并行执行所有请求,某个请求失败不会影响其他请求的执行,最后统一收集所有错误。这种方式效率更高,适合对顺序无要求的场景。

代码示例(Kotlin)

// 定义失败请求的缓存接口
interface FailedRequestCache {
    fun save(request: FailedPostRequest)
    fun getAll(): List<FailedPostRequest>
    fun remove(request: FailedPostRequest)
}

// 失败请求的模型,保存重发所需的全部信息
data class FailedPostRequest(
    val url: String,
    val body: RequestBody,
    val headers: Headers,
    val tag: String? = null // 可选:标记请求类型,方便分类处理
)

// 单个POST请求的执行逻辑:失败缓存,成功移除缓存
private fun executePost(
    apiService: ApiService,
    request: FailedPostRequest,
    cache: FailedRequestCache
): Observable<Response<Any>> {
    return apiService.post(request.url, request.body, request.headers)
        .doOnError { cache.save(request) } // 失败存入缓存
        .doOnNext { cache.remove(request) } // 成功移除缓存
}

// 处理有序请求队列:单个失败不阻塞
fun processOrderedQueue(
    apiService: ApiService,
    requests: List<FailedPostRequest>,
    cache: FailedRequestCache
): Observable<Response<Any>> {
    return Observable.fromIterable(requests)
        .concatMapEager { request ->
            executePost(apiService, request, cache)
                .onErrorResumeNext { Observable.empty() } // 捕获错误,队列继续
        }
}

// 批量并行重发缓存请求:失败不影响其他请求
fun retryCachedRequests(
    apiService: ApiService,
    cache: FailedRequestCache
): Completable {
    val completables = cache.getAll().map { request ->
        apiService.post(request.url, request.body, request.headers)
            .doOnComplete { cache.remove(request) }
            .doOnError { /* 可选:记录错误,或重新缓存(比如网络仍不可用) */ }
            .ignoreElements() // 转为Completable,只关注完成/失败
    }
    return Completable.mergeDelayError(completables)
}

关键注意事项

  • 错误隔离:必须在单个请求的Observable内部捕获错误,避免错误冒泡到队列流导致整个队列终止。
  • 缓存完整性:失败请求的模型要包含重发所需的全部信息(URL、请求体、头部、参数等),确保重发请求与原请求完全一致。
  • 重发时机:可以结合网络状态监听(如Android的ConnectivityManager),在网络恢复时自动触发重发;也可以提供手动触发入口。
  • 顺序控制:对顺序有要求用concatMapEager,无要求用flatMap+mergeDelayError,平衡顺序性和执行效率。

内容的提问来源于stack exchange,提问作者Konstantin Konopko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 08:17:38