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

Kotlin Flow异常处理扩展函数如何添加跨页面可调用的重试回调?

Kotlin Flow 错误重试实现方案

完全可以实现需求,推荐用「重试事件触发器 + Flow内置retryWhen操作符」的方案,不需要额外给已失败的Flow绑定回调,具体实现逻辑如下:


核心思路

  • 原生catch操作符仅能捕获上游异常并终止流,无法重启上游执行,因此配合retryWhen操作符实现流的重试逻辑
  • 每个流实例分配唯一ID,通过事件总线匹配错误事件和重试事件,实现跨页面/全局触发重试
  • 冷流特性保证重试时会重新执行上游逻辑,符合重新发起网络请求的需求

实现代码

1. 定义事件结构与全局事件总线

import kotlinx.coroutines.flow.MutableSharedFlow
import java.util.UUID

// 错误上报事件,携带流唯一标识、重试权限、异常本身
data class FlowErrorEvent(
    val requestId: String,
    val supportRetry: Boolean,
    val throwable: Throwable
)
// 重试触发事件,对应要重试的流ID
data class FlowRetryEvent(val requestId: String)

// 全局事件总线,配置缓冲区防止事件丢失
object FlowEventBus {
    val errorEvents = MutableSharedFlow<FlowErrorEvent>(extraBufferCapacity = 16)
    val retryEvents = MutableSharedFlow<FlowRetryEvent>(extraBufferCapacity = 16)
    
    suspend fun postError(event: FlowErrorEvent) = errorEvents.emit(event)
    suspend fun postRetry(event: FlowRetryEvent) = retryEvents.emit(event)
}

2. 改造Flow错误处理扩展函数

import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.retryWhen
import retrofit2.HttpException

fun <T> Flow<T>.handleErrors(
    showError: Boolean = false,
    retry: Boolean = false,
    navigateBack: Boolean = true,
    maxRetryCount: Int = 3 // 可选:限制最大重试次数
): Flow<T> {
    // 为每个流实例生成唯一ID,用来匹配重试事件
    val requestId = UUID.randomUUID().toString()
    var retryCount = 0 // 重试计数器
    return this
        .retryWhen { throwable, _ ->
            // 仅满足重试条件时监听重试事件
            if (retry && throwable is HttpException && retryCount < maxRetryCount) {
                // 收到对应ID的重试事件后返回true,触发上游流重新订阅执行
                retryEvents.first { it.requestId == requestId }
                retryCount++
                true
            } else {
                // 不满足重试条件则交给下游catch处理
                false
            }
        }
        .catch { throwable ->
            if (showError) {
                // 上报错误事件给Base层弹框
                FlowEventBus.postError(
                    FlowErrorEvent(
                        requestId = requestId,
                        supportRetry = retry && retryCount < maxRetryCount,
                        throwable = throwable
                    )
                )
            }
            // 原有其他逻辑:页面返回、普通提示等
            if (navigateBack) {
                // 你的页面返回逻辑
            }
            // 可根据需求选择是否重新抛出异常
            throw throwable
        }
}

3. Base层接收事件弹框与触发重试

// BaseActivity中监听错误事件弹框
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        FlowEventBus.errorEvents.collect { event ->
            AlertDialog.Builder(this@BaseActivity)
                .setMessage(getErrorMessage(event.throwable))
                .apply {
                    if (event.supportRetry) {
                        setPositiveButton("重试") { _, _ ->
                            lifecycleScope.launch {
                                // 发送对应ID的重试事件,触发流重启
                                FlowEventBus.postRetry(FlowRetryEvent(event.requestId))
                            }
                        }
                    }
                    setNegativeButton("取消") { _, _ ->
                        // 取消逻辑,需要返回的话直接finish
                    }
                }
                .setCancelable(false)
                .show()
        }
    }
}

注意事项

  • 如果不需要全局跨页面触发重试,可以把事件总线替换为ViewModel内的SharedFlow,作用域更安全
  • 页面销毁时只要取消对应Flow的订阅,就不会触发无效重试
  • 重试逻辑仅对冷流生效,热流需要根据实际场景调整上游重启逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 17:27:04