评论

收藏

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

移动开发 移动开发 发布于:2021-11-23 11:49 | 阅读数:512 | 评论:0

上篇文章讲解了怎么使用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发送请求

关注下面的标签,发现更多相似文章