当前位置: 首页 > 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 = 0Lvar shallRetry: Booleando {shallRetry = falseval cause = catchImpl(this)if (cause != null) {if (predicate(cause, attempt)) {shallRetry = trueattempt++} 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 = 0Lvar shallRetry: Booleando {shallRetry = falsetry {collect {if (attempt < retries && predicate(it)) {shallRetry = trueattempt++} 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 ->}}

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

http://www.lryc.cn/news/536265.html

相关文章:

  • 好好说话:深度学习扫盲
  • 【状态空间方程】对于状态空间方程矩阵D≠0时的状态反馈与滑模控制
  • 腾讯大数据基于 StarRocks 的向量检索探索
  • Linux系统调用
  • 如何在Servlet容器中使用HttpServletResponse?
  • SpringCloud - Seata 分布式事务
  • Ansible批量配置服务器免密登录步骤详解
  • 互联网大厂中面试的高频计算机网络问题及详解
  • 人工智能时代下ai智能语音机器人如何以假乱真?
  • 【橘子ES】Aggregations 聚合准备
  • vue3读取webrtc-stream 视频流
  • springcloud集成gateway
  • 2025常用的SEO工具有哪些?
  • C++类和对象进阶:运算符重载深度详解
  • Mybatisplus——Mybatisplus3.5.2版本使用Page分页插件查询,records有数据但是total显示0
  • C#(Winform)通过添加AForge添加并使用系统摄像机
  • AI使用场景简单测试
  • Linux 配置 MySQL 定时自动备份到另一台服务器
  • PostgreSQL 备库的延迟问题
  • 力扣-二叉树-226 翻转二叉树
  • 基于SpringBoot的在线车辆租赁信息管理系统
  • 掌握 systemd:Linux 服务管理的核心工具
  • 【信息系统项目管理师-案例真题】2019下半年案例分析答案和详解
  • C/C++程序的内存是如何开辟的?
  • 日志结构化处理:PO对象toString日志转JSON工具
  • python学opencv|读取图像(六十五)使用cv2.boundingRect()函数实现图像轮廓矩形标注
  • 大疆无人机需要的kml文件如何制作kml导出(大疆KML文件)
  • ArrayList、LinkedList、HashMap、HashTable、HashSet、TreeSet
  • 手动配置IP
  • idea如何使用AI编程提升效率-在IntelliJ IDEA 中安装 GitHub Copilot 插件的步骤-卓伊凡