Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/232.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 网络错误改造的异常处理_Android_Kotlin_Kotlin Coroutines - Fatal编程技术网

Android 网络错误改造的异常处理

Android 网络错误改造的异常处理,android,kotlin,kotlin-coroutines,Android,Kotlin,Kotlin Coroutines,我想知道在使用协同路由时,处理改装请求中的网络错误的最佳方法是什么 经典方法是在发出请求时在最高级别处理异常: try { // retrofit request } catch(e: NetworkException) { // show some error message } 我发现这个解决方案是错误的,它添加了很多样板代码,相反,我创建了一个返回错误响应的拦截器: class ErrorResponse : Interceptor { override fun

我想知道在使用协同路由时,处理改装请求中的网络错误的最佳方法是什么

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

try {
    // retrofit request
} catch(e: NetworkException) {
    // show some error message
}
我发现这个解决方案是错误的,它添加了很多样板代码,相反,我创建了一个返回错误响应的拦截器:

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()
        }
    }
}
这个解决方案稍微好一点,但是我认为它可以改进


所以我的问题是:当用户没有互联网连接时,如果没有很多样板代码(最好是在连接错误的情况下使用全局处理程序),正确的处理方法是什么。但只要稍作更改,您就可以使用以下示例类:

class NetworkConnectionInterceptor(val context: Context) : Interceptor {

    @Suppress("DEPRECATION")
    private val isConnected: Boolean
        get() {
            var result = false
            val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                cm?.run {
                    cm.getNetworkCapabilities(cm.activeNetwork)?.run {
                        result = when {
                            hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
                            hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
                            hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
                            else -> false
                        }
                    }
                }
            } else {
                cm?.run {
                    cm.activeNetworkInfo?.run {
                        if (type == ConnectivityManager.TYPE_WIFI) {
                            result = true
                        } else if (type == ConnectivityManager.TYPE_MOBILE) {
                            result = true
                        }
                    }
                }
            }
            return result
        }

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        if (!isConnected) {
            // Throwing your custom exception
            // And handle it on onFailure
        }

        val builder = chain.request().newBuilder()
        return chain.proceed(builder.build())
    }
}
然后将其添加到您的
OkHttpClient.Builder()

如果出现故障,您可以使用以下方法处理故障:

override fun onFailure(call: Call<BaseModel>, t: Throwable) {
    if (t is NoConnectivityException) {
        // Handle it here :)
    }
}
override-fun-onFailure(call:call,t:Throwable){
if(t为无连接异常){
//在这里处理:)
}
}

使用结果包装我的响应

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>()}
处理例外的扩展

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()
}}
首先,我们应该创建一个数据类来模拟响应体

data class HttpErrorEntity(
@SerializedName("message") val errorMessage: String,
@SerializedName("status") val errorCode: Int
)
下面是
asNetworkException
实现:

private fun asNetworkException(ex: Throwable): ErrorHolder {
    return when (ex) {
        is IOException -> {
            ErrorHolder.NetworkConnection(
                "No Internet Connection"
            )
        }
        is HttpException -> extractHttpExceptions(ex)
        else -> ErrorHolder.UnExpected("Something went wrong...")
    }
}

private fun extractHttpExceptions(ex: HttpException): ErrorHolder {
    val body = ex.response()?.errorBody()
    val gson = GsonBuilder().create()
    val responseBody= gson.fromJson(body.toString(), JsonObject::class.java)
    val errorEntity = gson.fromJson(responseBody, HttpErrorEntity::class.java)
    return when (errorEntity.errorCode) {
        ErrorCodes.BAD_REQUEST.code -> 
                ErrorHolder.BadRequest(errorEntity.errorMessage)
            
        ErrorCodes.INTERNAL_SERVER.code -> 
            ErrorHolder.InternalServerError(errorEntity.errorMessage)
        
        ErrorCodes.UNAUTHORIZED.code ->
            ErrorHolder.UnAuthorized(errorEntity.errorMessage)
       
        ErrorCodes.NOT_FOUND.code ->
            ErrorHolder.ResourceNotFound(errorEntity.errorMessage)
        
        else -> 
            ErrorHolder.Unknown(errorEntity.errorMessage)
        
    }
}

我希望避免手动检查网络连接,因为它需要单独的权限。这也不能解决您必须处理异常的问题。@Daniel如果不手动检查网络连接,您必须检查异常实例的改装调用
IOException
方法。虽然这包括另一个错误,但不仅仅是脱机错误。您可以添加asNetworkException()乐趣实现吗?请有兴趣了解如何处理错误案例感谢Sprivate fun asNetworkException(throwable:throwable):ErrorHolder{return ErrorHolder.NetworkConnection(throwable=throwable,message=throwable.message?:“Empty error message”)}@MohammadSianaki您缺少错误保持器上的意外值,ErrorCodes类是否这只是一堆静态字符串,如400 for error等?@MohammadSianaki我在结果上使用此字符串时也会出错。成功:在构造函数成功中键入为T绑定的参数(值:T)不满足:推断类型R不是的子类型Any@martinseal1987kotlin标准库有自己的结果类型,请确保您正在导入自己的类型,而不是从标准库导入的类型。
suspend fun fetchUsers(): Result<List<User>> {
    return service.getUsers().awaitResult { usersResponseDto ->
        usersResponseDto.toListOfUsers()
    }
}
{
  "error" : {
    "status" : 502,
    "message" : "Bad gateway."
  }
}
data class HttpErrorEntity(
@SerializedName("message") val errorMessage: String,
@SerializedName("status") val errorCode: Int
)
private fun asNetworkException(ex: Throwable): ErrorHolder {
    return when (ex) {
        is IOException -> {
            ErrorHolder.NetworkConnection(
                "No Internet Connection"
            )
        }
        is HttpException -> extractHttpExceptions(ex)
        else -> ErrorHolder.UnExpected("Something went wrong...")
    }
}

private fun extractHttpExceptions(ex: HttpException): ErrorHolder {
    val body = ex.response()?.errorBody()
    val gson = GsonBuilder().create()
    val responseBody= gson.fromJson(body.toString(), JsonObject::class.java)
    val errorEntity = gson.fromJson(responseBody, HttpErrorEntity::class.java)
    return when (errorEntity.errorCode) {
        ErrorCodes.BAD_REQUEST.code -> 
                ErrorHolder.BadRequest(errorEntity.errorMessage)
            
        ErrorCodes.INTERNAL_SERVER.code -> 
            ErrorHolder.InternalServerError(errorEntity.errorMessage)
        
        ErrorCodes.UNAUTHORIZED.code ->
            ErrorHolder.UnAuthorized(errorEntity.errorMessage)
       
        ErrorCodes.NOT_FOUND.code ->
            ErrorHolder.ResourceNotFound(errorEntity.errorMessage)
        
        else -> 
            ErrorHolder.Unknown(errorEntity.errorMessage)
        
    }
}