2017-10-22 32 views
5

Tôi đang sử dụng Kotlin coroutines cho yêu cầu mạng sử dụng phương pháp khuyến nông để gọi lớp trong trang bị thêm như thế nàyLàm thế nào để Exponential Backoff thử lại trên Kotlin coroutines

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

sau đó từ gọi phía tôi đang sử dụng phương pháp nêu trên như thế này

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 
    } 

} 

tôi muốn thử lại hàm mũ api này trong một số trường hợp tức là (IOException) làm cách nào tôi có thể đạt được nó?

Trả lời

22

Tôi khuyên bạn nên viết helper higher-order function cho logic thử lại của bạn. Bạn có thể sử dụng việc thực hiện sau đây cho một sự khởi đầu:

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 
} 

Sử dụng chức năng này là rất strightforward:

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

Bạn có thể thay đổi các thông số thử lại trên cơ sở từng trường hợp cụ thể, ví dụ:

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

Bạn cũng có thể thay đổi hoàn toàn việc triển khai retryIO để phù hợp với nhu cầu của ứng dụng của bạn. Ví dụ: bạn có thể mã hóa cứng tất cả các tham số thử lại, loại bỏ giới hạn về số lần thử lại, thay đổi mặc định, v.v.

+0

mẹo trả lời rất gọn gàng nhờ –

+1

Đây là thứ ở phía sau đầu của tôi vài ngày rồi. Rất vui khi thấy giải pháp không phức tạp hơn những gì tôi đang tưởng tượng. Tôi cũng đã tự hỏi liệu việc định nghĩa hàm trợ giúp này là một hàm nội tuyến có ý nghĩa không. Và cuối cùng nhưng không kém phần quan trọng: làm thế nào để sửa đổi, nếu bạn muốn thực hiện thử lại chỉ sau khi yêu cầu người dùng làm như vậy (ví dụ như trong một cuộc đối thoại)? –

+1

Cũng sạch hơn nhiều so với giải pháp Rx: -O – kenyee

Các vấn đề liên quan