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

我正在使用扩展方法在网络请求中使用kotlin协同程序来调用类

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

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

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

您也可以彻底更改retryIO的实现以适合您的应用程序的需求。 例如,您可以硬编码所有的重试参数,摆脱重试次数限制,更改默认值等。