网络错误改造的异常处理 [英] Exception handling of network errors retrofit

查看:120
本文介绍了网络错误改造的异常处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道使用协程时在改造请求中处理网络错误的最佳方法是什么.

I was wondering what is the best way to handle network errors in retrofit requests when using coroutines.

经典方法是在发出请求时在最高级别处理异常:

The classic way is handling exception at highest level, when a request is made:

try {
    // retrofit request
} catch(e: NetworkException) {
    // show some error message
}

我发现此解决方案是错误的,它添加了许多样板代码,而是创建了一个返回错误响应的拦截器:

I find this solution wrong and it adds a lot of boilerplate code, instead I went with creating an interceptor that returns a error response:

class ErrorResponse : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        return try {
            chain.proceed(request)
        } catch (e: Exception) {
            Snackbar.make(
                view,
                context.resources.getText(R.string.network_error),
                Snackbar.LENGTH_LONG
            ).show()
            Response.Builder()
                .request(request)
                .protocol(Protocol.HTTP_1_1)
                .code(599)
                .message(e.message!!)
                .body(ResponseBody.create(null, e.message!!))
                .build()
        }
    }
}

此解决方案要好一些,但是我认为它可以改进.

This solution is a little better, however I think that it can be improved.

所以我的问题是:在没有大量样板代码的情况下(如果发生连接错误,最好使用全局处理程序)处理用户没有互联网连接的情况的正确方法是什么?

So my question is: What is the correct way to handle the cases when user doesn't have internet connection, without a lot of boilerplate code (ideally with a global handler in case of connection errors) ?

推荐答案

使用结果"包装我的回复

Using Result to wrap my response

sealed class Result<out T : Any> {
data class Success<out T : Any>(val value: T) : Result<T>()
data class Failure(val errorHolder:ErrorHolder) : Result<Nothing>()}

ErrorHolder:

ErrorHolder :

sealed class ErrorHolder(override val message):Throwable(message){
 data class NetworkConnection(override val message: String, val throwable: Throwable) : ErrorHolder(message)
 data class BadRequest(override val message: String, val throwable: Throwable) : ErrorHolder(message)
}

用于处理例外的扩展

suspend fun <T, R> Call<T>.awaitResult(map: (T) -> R): Result<R> = suspendCancellableCoroutine { continuation ->
try {
    enqueue(object : Callback<T> {
        override fun onFailure(call: Call<T>, throwable: Throwable) {
            errorHappened(throwable)
        }

        override fun onResponse(call: Call<T>, response: Response<T>) {
            if (response.isSuccessful) {
                try {
                    continuation.resume(Result.Success(map(response.body()!!)))
                } catch (throwable: Throwable) {
                    errorHappened(throwable)
                }
            } else {
                errorHappened(HttpException(response))
            }
        }

        private fun errorHappened(throwable: Throwable) {
            continuation.resume(Result.Failure(asNetworkException(throwable)))
        }
    })
} catch (throwable: Throwable) {
    continuation.resume(Result.Failure(asNetworkException(throwable)))
}

continuation.invokeOnCancellation {
    cancel()
}}

这就是我进行api调用的方式:

And this how I make the api call:

suspend fun fetchUsers(): Result<List<User>> {
    return service.getUsers().awaitResult { usersResponseDto ->
        usersResponseDto.toListOfUsers()
    }
}

这篇关于网络错误改造的异常处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆