2017-10-22 2 views
5

Ich bin mit Kotlin Koroutinen für Netzwerkanforderung Klasse wie diese von der Seite ruft dann Wie Backoff auf Kotlin wiederholen exponentiellen Koroutinen

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

in der Nachrüstung mit Erweiterung Methode aufrufen i wie dieses

obige Verfahren verwende
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 
    } 

} 

Ich möchte diesen API-Aufruf in einigen Fällen exponentiell wiederholen ie (IOException) wie kann ich es erreichen ??

Antwort

22

Ich würde vorschlagen, einen Helfer higher-order function für Ihre Wiederholungslogik zu schreiben. Sie können für einen Start die folgenden Implementierung verwenden:

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 
} 

Mit dieser Funktion ist sehr Entlehnung:

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

Sie Wiederholungs Parameter auf Basis von Fall zu Fall ändern können, zum Beispiel:

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

Sie können die Implementierung von retryIO auch vollständig ändern, um die Anforderungen Ihrer Anwendung zu erfüllen. Zum Beispiel können Sie alle Wiederholungs-Parameter hart codieren, das Limit für die Anzahl der Wiederholungen entfernen, die Standardwerte ändern usw.

+0

wow sehr saubere Antwort danke –

+1

Das war etwas, das mir im Hinterkopf lag einige Tage jetzt. Schön zu sehen, dass die Lösung nicht komplexer ist als das, was ich mir vorgestellt habe. Ich fragte mich auch, ob es sinnvoll wäre, diese Hilfsfunktion als Inline-Funktion zu definieren. Und last but not least: Wie sollte das a modifiziert werden, wenn Sie den Wiederholungsversuch nur nach Aufforderung des Benutzers (zB in einem Dialog) durchführen wollen? –

+1

Auch so viel sauberer als die Rx-Lösung: -O – kenyee

Verwandte Themen