我正在使用kotlin协同路由进行网络请求,使用扩展方法在这样的 retrofit 中调用类

public suspend fun <T : Any> Call<T>.await(): T {

  return suspendCancellableCoroutine { continuation -> 

    enqueue(object : Callback<T> {

        override fun onResponse(call: Call<T>?, response: Response<T?>) {
            if (response.isSuccessful) {
                val body = response.body()
                if (body == null) {
                    continuation.resumeWithException(
                            NullPointerException("Response body is null")
                    )
                } else {
                    continuation.resume(body)
                }
            } else {
                continuation.resumeWithException(HttpException(response))
            }
        }

        override fun onFailure(call: Call<T>, t: Throwable) {
            // Don't bother with resuming the continuation if it is already cancelled.
            if (continuation.isCancelled) return
            continuation.resumeWithException(t)
        }
    })

      registerOnCompletion(continuation)
  }
}

then from calling side i am using above method like this

private fun getArticles()  = launch(UI) {

    loading.value = true
    try {
        val networkResult = api.getArticle().await()
        articles.value =  networkResult

    }catch (e: Throwable){
        e.printStackTrace()
        message.value = e.message

    }finally {
        loading.value = false
    }

}

i want to exponential retry this api call in some case i.e (IOException) how can i achieve it ??

推荐答案

我建议为您的重试逻辑编写一个帮助器higher-order function.您可以使用以下实现作为起点:

suspend fun <T> retryIO(
    times: Int = Int.MAX_VALUE,
    initialDelay: Long = 100, // 0.1 second
    maxDelay: Long = 1000,    // 1 second
    factor: Double = 2.0,
    block: suspend () -> T): T
{
    var currentDelay = initialDelay
    repeat(times - 1) {
        try {
            return block()
        } catch (e: IOException) {
            // you can log an error here and/or make a more finer-grained
            // analysis of the cause to see if retry is needed
        }
        delay(currentDelay)
        currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay)
    }
    return block() // last attempt
}

使用此函数非常简单:

val networkResult = retryIO { api.getArticle().await() }

您可以根据具体情况更改重试参数,例如:

val networkResult = retryIO(times = 3) { api.doSomething().await() }

You can also completely change the implementation of retryIO to suit the needs of your application. For example, you can hard-code all the retry parameters, get rid of the limit on the number of retries, change defaults, etc.

Kotlin相关问答推荐

Lambda和普通Kotlin函数有什么区别?

如果一项工作失败,请继续在Kotlin 等待其他工作/子元素完成

使用数据存储首选项Kotlin Jetpack Compose

将文本与文本字段的内容对齐

Kotlin异步不并行运行任务

使用另一个对象的列表创建对象

同时也是一个字符串的 Kotlin 枚举

当 func 重载时,kotlin 如何确定调用哪个 func?

使用启动或使用 coroutineScope 启动协程之间的区别

使用 Compose for Desktop Bundle 文件

匹配在单词边界上包含特殊字符的变量字符串的正则表达式

是否可以通过超时暂停协程?

kotlin 扩展属性的惰性初始化器中的这个引用

TextField maxLength - Android Jetpack Compose

Android Studio 将 Java 转换为 Kotlin 错误无法推断此参数的类型

launch 仅从 Kotlin 1.3 开始可用,不能在 Kotlin 1.2 中使用

Kotlin通过映射委托属性,如果映射中不存在,则抛出NoTouchElementException

如何为kotlin异常生成SerialVersionId?

如何从协程范围返回值

Dagger 2 androidx fragment不兼容类型