安卓开发-封装处理Retrofit协程请求中的异常
上篇文章讲解了怎么使用Kotlin
的协程配合Retrofit
发起网络请求,使用也是非常方便,但是在处理请求异常还不是很人性化。这篇文章,我们将处理异常的代码进行封装,以便对异常情况返回给页面,提供更加友好的提示。
编写拓展方法
我们写一个扩展(全局)方法,就叫ViewModelExt.kt
,在下面创建方法。
fun ViewModel.launch( block: suspend CoroutineScope.() -> Unit, onError: (e: Throwable) -> Unit = { _: Throwable -> }, onComplete: () -> Unit = {} ) { viewModelScope.launch( CoroutineExceptionHandler { _, throwable -> run { ExceptionUtil.catchException(throwable) onError(throwable) } } ) { try { block.invoke(this) } finally { onComplete() } } }
|
统一异常处理
拓展方法里面对写成过程做了统一拦截,在onComplete
方法可以做统一的异常处理
object ExceptionUtil {
fun catchException(e: Throwable) { e.printStackTrace() when (e) { is HttpException -> { catchHttpException(e.code()) } is SocketTimeoutException -> { showToast(R.string.common_error_net_time_out) } is UnknownHostException, is NetworkErrorException -> { showToast(R.string.common_error_net) } is MalformedJsonException, is JsonSyntaxException -> { showToast(R.string.common_error_server_json) } is InterruptedIOException -> { showToast("服务器连接失败,请稍后重试") } is ApiException -> { showToast(e.message?:"", e.code) } is ConnectException -> { showToast( "连接服务器失败" ) } else -> { showToast("${MyApplication.instance.getString( R.string.common_error_do_something_fail )}:${e::class.java.name}") } } }
fun catchHttpException(errorCode: Int) { if (errorCode in 200 until 300) return showToast( catchHttpExceptionCode( errorCode ), errorCode ) }
private fun showToast(@StringRes errorMsg: Int, errorCode: Int = -1) { showToast( MyApplication.instance.getString( errorMsg ), errorCode ) }
private fun showToast(errorMsg: String, errorCode: Int = -1) { if (errorCode == -1) { ToastUtils.showShort(errorMsg) } else { ToastUtils.showShort("$errorCode:$errorMsg") } }
private fun catchHttpExceptionCode(errorCode: Int): Int = when (errorCode) { in 500..600 -> R.string.common_error_server in 400 until 500 -> R.string.common_error_request else -> R.string.common_error_request } }
|
ApiException
是自定义的异常类
如何使用
我们在一个ViewModel
中可以这样使用
fun login(user: User) = launch({ val resultData = RetrofitClient.userService.login(user) if (resultData.code == 20000) { userInfo.value = RetrofitClient.userService.getUserInfo().data } },onError = { e: Throwable ->
})
|
注意:我们在ViewModel的拓展方法中已经进行了协程调用操作,所以这里直接调用拓展方法即可。
如果是返回的结果不对,可以这样做
fun login(user: User) = launch({ val resultData = RetrofitClient.userService.login(user) if (resultData.code == 20000) { userInfo.value = RetrofitClient.userService.getUserInfo().data } else { throw ApiException(-1, "返回结果出错") } },onError = { e: Throwable -> })
|
ApiException
是自定义的异常处理,该异常同样会被拦截,进入onError中,可以在这里进行处理。