如何在kotlin协程上重复指数退避重试

我正在使用kotlin协程用于网络请求,使用扩展方法在这样的改造中调用类

public suspend fun  Call.await(): T { return suspendCancellableCoroutine { continuation -> enqueue(object : Callback { override fun onResponse(call: Call?, response: Response) { 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: Throwable) { // Don't bother with resuming the continuation if it is already cancelled. if (continuation.isCancelled) return continuation.resumeWithException(t) } }) registerOnCompletion(continuation) } } 

然后从呼叫方我使用这样的上述方法

 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 } } 

我希望在某些情况下指数重试此api调用即(IOException)如何实现它?

我建议为你的重试逻辑编写一个帮助程序高阶函数 。 您可以使用以下实现来开始:

 suspend fun  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 } 

使用此function非常简单:

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

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

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

您还可以完全更改retryIO的实现以满足应用程序的需要。 例如,您可以对所有重试参数进行硬编码,除去重试次数限制,更改默认值等。