飞奔的炮台 发表于 2021-11-23 11:49:21

安卓开发封装处理Retrofit协程请求中的异常

上篇文章讲解了怎么使用Kotlin的协程配合Retrofit发起网络请求,使用也是非常方便,但是在处理请求异常还不是很人性化。这篇文章,我们将处理异常的代码进行封装,以便对异常情况返回给页面,提供更加友好的提示。
编写拓展方法
我们写一个扩展(全局)方法,就叫ViewModelExt.kt,在下面创建方法。
/**
* ViewModel扩展方法:启动协程
* @param block 协程逻辑
* @param onError 错误回调方法
* @param onComplete 完成回调方法
*/
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方法可以做统一的异常处理
/**
* 异常工具类
* @author ssq
*/
object ExceptionUtil {

    /**
   * 处理异常,toast提示错误信息
   */
    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// 成功code则不处理
      showToast(
            catchHttpExceptionCode(
                errorCode
            ), errorCode
      )
    }

    /**
   * toast提示
   */
    private fun showToast(@StringRes errorMsg: Int, errorCode: Int = -1) {
      showToast(
            MyApplication.instance.getString(
                errorMsg
            ), errorCode
      )
    }

    /**
   * toast提示
   */
    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 ->

})
如果是返回的结果不对,可以这样做
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是自定义的异常处理

使用Demo:
上篇文章:使用Kotlin协程配合Retrofit发送请求

https://www.cnblogs.com/sw-code/p/15591713.html
页: [1]
查看完整版本: 安卓开发封装处理Retrofit协程请求中的异常