How to retry HTTP requests with OkHttp/Retrofit in Android with Kotlin
Tags: mobile, kotlin, android, tristan
Published: 2024-01-29 00:04:12

### Table of contents
1. [Too long didn't read. Give me the code!!!](#tldr)
2. [The problem I am trying to solve](#solve)
3. [The RetryInterceptor](#interceptor)
4. [Make the request](#request)
5. [The while loop](#while)
6. [Retry the request](#retry)
7. [Throwing exceptions](#throw)
8. [WARNING!!!](#warning)


### Resources
- I got all the information from this [Stackoverflow question](https://stackoverflow.com/questions/24562716/how-to-retry-http-requests-with-okhttp-retrofit)


### My app on the Google play store
- [The app](https://play.google.com/store/apps/details?id=elliott.software.clicker)


###GitHub code <a name="tldr"></a>
- [Entire GitHub application code](https://github.com/thePlebDev/Clicker)
- [Full GitHub RetryInterceptor code](https://github.com/thePlebDev/Clicker/blob/176235599007bd6b85514cc63d1984878abcce46/app/src/main/java/com/example/clicker/network/interceptors/RetryInterceptor.kt#L10)

### The problem I am trying to solve <a name="solve"></a>
- As a mobile developers our user are.... well.... mobile. Which means there will come times when a request will fail for any number of reasons. A slow network, they walk under a bridge just as a request is being made, or any other scenario where the request fails and the remedy would be to simply make another request.
- So to combat these situations we are going to create an [Interceptor](https://square.github.io/okhttp/features/interceptors/) that will be able make 3 repeat requests if the initial request fails.


### The RetryInterceptor <a name="interceptor"></a>
- [Full GitHub code](https://github.com/thePlebDev/Clicker/blob/176235599007bd6b85514cc63d1984878abcce46/app/src/main/java/com/example/clicker/network/interceptors/RetryInterceptor.kt#L10)
- The full Interceptor code looks like this:
```
class RetryInterceptor(private val maxRetries: Int) : Interceptor {

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {

            val request = chain.request()
            // try the request
            var response = chain.proceed(request)

            var tryCount = 0;
            while (!response.isSuccessful && tryCount < maxRetries) {
                Log.d("StartingInterception","$tryCount")
                tryCount++

                // retry the request
                response.close()
                response = chain.proceed(request);
            }
            if(tryCount == maxRetries){

                throw(IOException("Error. Please try again"))

            }
            return response


    }

}

```
- Now lets break down this code:

### 1) make the request <a name="request"></a>

`1) make the request`: The first thing we need to do is try the request and this is done with this section of code:
```
val request = chain.request()
// try the request
var response = chain.proceed(request)

```
- This is what is doing the actual request. `chain.request()` is grabbing the request and then `chain.proceed(request)` is actually making the call to the HTTP server

### 2) The while loop <a name="while"></a>
`2) The while loop `: The while loop's conditional is that the response has to be unsuccessful and tryCount has to be less than the maxRetries: `!response.isSuccessful && tryCount < maxRetries`

### 3) Retry the request <a name="retry"></a>
`3) Retry the request: ` In the while loop we need to do three things, `1) increase the tryCount`,`2) close the old response`, `3)make another request`:
```
//1) increase the tryCount
tryCount++
//2) close the old response. Failing to do this will cause a crash
response.close()
//3) make another request. This assigns a new response each interation
response = chain.proceed(request);
```
- Now the while loop will continue until the response is successful or the tryCount is equal to the maxRetries

### 4) Throwing exceptions <a name="throw"></a>
`4) Throwing exceptions`: So lastly if `tryCount == maxRetries` the code throws an exception. It might seem weird that I am not handling exceptions here. However, I am handling the exceptions in a different part of my code. Specifically the network layer
- [GitHub network layer exception handling code in action](https://github.com/thePlebDev/Clicker/blob/176235599007bd6b85514cc63d1984878abcce46/app/src/main/java/com/example/clicker/network/repository/TwitchAuthenticationImpl.kt#L68)
- [GitHub network layer exception handling code definition](https://github.com/thePlebDev/Clicker/blob/176235599007bd6b85514cc63d1984878abcce46/app/src/main/java/com/example/clicker/network/repository/util/ExceptionHandling.kt#L34)

### WARNING <a name="warning"></a>
- This is not the only situation your interceptor should handle!!!
- You should also have interceptors that check for `Network availability` and `401 responses`
- I will also be writing blog posts about these scenarios.

### Conclusion 
- Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on [Twitter](https://twitter.com/AndroidTristan).