2

I understand how to handle errors when not using coroutines:

@GET("user/{user}")
fun getHomeData(@Path("user") user: String?): Call<HomeDataBody>



fun getHomeData(id:String, callback: (Boolean, String?) -> Unit)
{
    val call = service.getHomeData(id)
    call.enqueue( object : Callback<HomeDataBody> {
        override fun onResponse(call: Call<HomeDataBody>, response: Response<HomeDataBody>)
        {
            if (response.isSuccessful)
            {
                dataMgr.homeData = response.body()!!.user

                callback(true, null)
            }
            else
            {
                callback(false, response.message())
            }
        }

        override fun onFailure(call: Call<HomeDataBody>, t: Throwable)
        {
            callback(false, t.message)
        }

    })
}

But I cannot for the life of me figure out how to do this with coroutines, this is what I have for a coroutine that does not return errors:

@GET("user/{user}")
suspend fun getHomeDataCoroutine(@Path("user") user: String?): HomeData


suspend fun getHomeDataCoroutine(id:String) : Pair<Boolean, String>
{
    val data = service.getHomeDataCoroutine(id)

    if(data != null)
    {
        dataMgr.homeData = data
    }
    else
    {
        return Pair(false, "how do i get the error message??")
    }

}

I also attempted this, but when I try to call service.getHomeDataCoroutine I get this error: java.lang.IllegalArgumentException: Unable to create call adapter for class java.lang.Object for method RiseServiceRetro.getHomeDataCoroutine

@GET("user/{user}")
suspend fun getHomeDataCoroutine(@Path("user") user: String?): Deferred<HomeDataBody>?

sealed class Result<out T : Any>
class Success<out T : Any>(val data: T) : Result<T>()
class Error(val exception: Throwable, val message: String =    exception.localizedMessage) : Result<Nothing>()

suspend fun getHomeDataCoroutine(id:String): Result<HomeDataBody>
{
    try {
        val response = service.getHomeDataCoroutine(id)!!.await()
        return Success(response)
    } catch (e: Exception) {
        return Error(e)
    }

}
user3561494
  • 2,164
  • 1
  • 20
  • 33
  • Does [this](https://stackoverflow.com/questions/54077592/kotlin-coroutines-handle-error-and-implementation) help? Also, I would suggest converting the logic inside getHomeDataCoroutine to a when statement. – tomerpacific Jun 06 '20 at 15:06
  • I attempted to adapt my code to that answer but getting an error message – user3561494 Jun 06 '20 at 21:14
  • When using `suspend fun` with Retrofit interfaces, the result wrapper type can be omitted, ie. instead of `Deferred?` you should use `HomeDataBody`. This might help for the `IllegalArgumentException`. The `await()` call shouldn't also be needed. – mrpasqal Jun 06 '20 at 21:31
  • According to my best knowledge, an exception should be thrown when the result is not 20x, so you should be able to handle it in the `catch` clause. What kind of error do you expect here? – mrpasqal Jun 06 '20 at 21:45
  • @mrpasqal I tried your suggestion but it gives the same error message. – user3561494 Jun 06 '20 at 21:46
  • Please see this https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-260-2019-06-05 – mrpasqal Jun 06 '20 at 21:54

1 Answers1

2

To handle errors when calling suspend function of Retrofit service wrap it in try-catch block:

@GET("user/{user}")
suspend fun getHomeDataCoroutine(@Path("user") user: String?): HomeDataBody

suspend fun getHomeDataCoroutine(id:String): Pair<Boolean, String> {
    return try {
        val data = service.getHomeDataCoroutine(id)
        dataMgr.homeData = data
        Pair(true, "")
    } catch(e: Throwable) {
        Pair(false, e.message ?: "error")
    }
}
Sergio
  • 27,326
  • 8
  • 128
  • 149