当前位置: 首页 > news >正文

基于Kotlin中Flow扩展重试方法

在这里插入图片描述
最近项目中统一采用Kotlin的Flow来重构了网络请求相关代码。
目前的场景是,接口在请求的时候需要一个accessToken值,因为此值会过期或者不存在,需要刷新,因此最终方案是在使用Flow请求的时候先获取accessToken值然后再进行接口请求,而获取accessToken值的方法已经封装成了一个Flow并且做了缓存,因此最后需要使用flatMapConcat操作符来连接真正需要的接口请求,如果获取的accessToken无效,又需要回头重新执行,逻辑如下:

  1. 判断本地是否存在accessToken并且是否过期,不存在或者已过期则请求accessToken
  2. 请求对应的接口
  3. 如果返回结果中accessToken无效,则重试

Flow提供了retryretryWhen两种扩展方法来做重试操作:

retry源码

public fun <T> Flow<T>.retry(
    retries: Long = Long.MAX_VALUE,
    predicate: suspend (cause: Throwable) -> Boolean = { true }
): Flow<T> {
    require(retries > 0) { "Expected positive amount of retries, but had $retries" }
    return retryWhen { cause, attempt -> attempt < retries && predicate(cause) }
}

retryWhen源码

public fun <T> Flow<T>.retryWhen(predicate: suspend FlowCollector<T>.(cause: Throwable, attempt: Long) -> Boolean): Flow<T> =
    flow {
        var attempt = 0L
        var shallRetry: Boolean
        do {
            shallRetry = false
            val cause = catchImpl(this)
            if (cause != null) {
                if (predicate(cause, attempt)) {
                    shallRetry = true
                    attempt++
                } else {
                    throw cause
                }
            }
        } while (shallRetry)
    }

但是,retryretryWhen只能通过异常来判断,如果是通过返回结果来判断,就需要借助外部变量来处理了,因此基于源码扩展了方法retry,可以接收请求结果,从而通过请求结果来判断是否需要重试。

fun <T> Flow<T>.retry(
    retries: Long = Long.MAX_VALUE, predicate: suspend (result: T) -> Boolean = { true }
): Flow<T> {
    require(retries > 0) { "Expected positive amount of retries, but had $retries" }
    return flow {
        var attempt = 0L
        var shallRetry: Boolean
        do {
            shallRetry = false
            try {
                collect {
                    if (attempt < retries && predicate(it)) {
                        shallRetry = true
                        attempt++
                    } else {
                        this.emit(it)
                    }
                }
            } catch (e: Throwable) {
                throw e
            }
        } while (shallRetry)
    }
}

最后的请求示例代码如下:

MainScope().launch {
        getToken().flatMapConcat {
            if (it is Result.Success) {
                sendMobileCode()
            } else {
                emptyFlow()
            }
        }.retry(1) {
            return@retry (it is Result.Failure) && (it.code == ErrorStatus.ACCESS_TOKEN_ERROR)
        }.flowOn(Dispatchers.IO).onStart {
            callback?.onStart()
        }.catch {
            callback?.onError(it)
        }.onCompletion {
            callback?.onComplete(it)
        }.collectLatest { result ->
        }
    }

感谢大家的支持,如有错误请指正,如需转载请标明原文出处!

相关文章:

  • 【代码随想录】第八章-贪心算法
  • docker compose快速部署kafka-connect集群
  • rdian是一个结构体,pdian=^Rdian,list泛型做什么用?
  • macOs安装nvm
  • 【Android开发】安卓手机APP使用机器学习进行QR二维码识别(完整工程资料源码)
  • 计算机网络结课设计:通过思科Cisco进行中小型校园网搭建
  • Jenkins 新建配置Pipeline任务 三
  • 计算机网络-MPLS转发原理
  • 【ISO 14229-1:2023 UDS诊断全量测试用例清单系列:第六节】
  • 查询语句来提取 detail 字段中包含 xxx 的 URL 里的 commodity/ 后面的数字串
  • Leetcode:学习记录
  • Javaweb中,使用Servlet编写简单的接口
  • leetcode 347. 前 K 个高频元素
  • C++STL(六)——list模拟
  • 左移架构 -- 从攒批,湖仓到使用数据流的实时数据产品
  • NPDP学习笔记 -产品经理(第二版)-第一章 战略
  • Linux——stdio
  • [MySQL]MySQL数据类型
  • Python实现随机森林(Random Forest)算法​
  • wordpress模板文件结构超详解
  • 彭阳门户网站建设/自己的网站
  • 网站域名到期后不续费会怎样/竞价网站
  • 做a动态网站/昆明seo网站管理
  • 网站的标签修改/免费刷赞网站推广qq免费
  • 个人网站建设论文中期报告/人工智能培训
  • 网商之窗麻将开挂/整站优化外包服务