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

安卓开发封装处理Retrofit协程请求中的异常的更多相关文章

  1. python自动化开发学习 进程, 线程, 协程

    python自动化开发学习 进程, 线程, 协程   前言 在过去单核CPU也可以执行多任务,操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换任务2,任务2执行0.01秒,在切换到任务3,这 ...

  2. python 全栈开发,Day43(引子,协程介绍,Greenlet模块,Gevent模块,Gevent之同步与异步)

    昨日内容回顾 I/O模型,面试会问到I/O操作,不占用CPU.它内部有一个专门的处理I/O模块.print和写log 属于I/O操作,它不占用CPU 线程GIL保证一个进程中的多个线程在同一时刻只有一 ...

  3. 封装你的协程Unity TaskManager

    unity5提供了协程,不过用起来很蛋疼,当然如果是unity2017 你就可以用async await了 提供一个TaskManager来封装协程(github  https://github.co ...

  4. Python协程(中)

    协程嵌套 使用async可以定义协程,协程用于耗时的io操作,我们也可以封装更多的io操作过程,这样就实现了嵌套的协程,即一个协程中await了另外一个协程,如此连接起来. import asynci ...

  5. 【Golang】如何统一处理HTTP请求中的异常捕获

    最近写GOLANG项目,不使用框架,路由选择httprouter 现在想实现一个需求:在不修改httprouter源码的前提下,对所有注册的路由handle进行异常捕获. 大家都知道golang使用p ...

  6. [日常] 使用TCPDUMP和Ethereal抓包分析HTTP请求中的异常情况

    在测试功能的过程中,出现这样一种现象.前端js发起ajax请求后,在浏览器的审查元素网络状态中可以看到status为pending,等15秒以后js会把当前超时的请求取消掉,变成了红色的cancel. ...

  7. Python全栈开发-Day10-进程/协程/异步IO/IO多路复用

    本节内容 多进程multiprocessing 进程间的通讯 协程 论事件驱动与异步IO Select\Poll\Epoll——IO多路复用   1.多进程multiprocessing Python ...

  8. RxHttp ,比Retrofit 更优雅的协程体验

    1.前言 Hello,各位小伙伴,又见面了,回首过去,RxHttp 就要迎来一周年生日了(19年4月推出),这一年,走过来真心....真心不容易,代码维护.写文章.写文档等等,经常都是干到零点之后,也 ...

  9. Python开发【第九章】:线程、进程和协程

    一.线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务 1.t ...

  10. Python开发基础-Day32 进程间通信、进程池、协程

    进程间通信 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的. 进程队列queue 不同于线程queue,进程 ...

随机推荐

  1. Python基于Excel数据加以反距离加权空间插值并掩膜图层

      本文介绍基于Python中ArcPy模块,实现Excel数据读取并生成矢量图层,同时进行IDW插值与批量掩膜的方法. 1 任务需求   首先,我们来明确一下本文所需实现的需求.   现有一个记录有 ...

  2. 掌握 xUnit 单元测试中的 Mock 与 Stub 实战

    引言 上一章节介绍了 TDD 的三大法则,今天我们讲一下在单元测试中模拟对象的使用. Fake Fake - Fake 是一个通用术语,可用于描述 stub或 mock 对象. 它是 stub 还是 ...

  3. 深入解析decltype和decltype(auto)

    decltype关键字是C++11新标准引入的关键字,它和关键字auto的功能类似,也可以自动推导出给定表达式的类型,但它和auto的语法有些不同,auto推导的表达式放在"="的 ...

  4. 把vim配置成顺手的python轻量级IDE(一)

    把vim配置成顺手的python轻量级IDE(一) 地球的外星人君 Linux云计算和Python推动市场提升的学习研究者. 分享一篇文章,正好最近正在折腾VIM,原文在把vim配置成顺手的pytho ...

  5. iNeuOS工业互联网操作系统,民爆远程运维平台案例

    iNeuOS工业互联网操作系统,民爆远程运维平台案例 目       录 1.      概述... 2 2.      iNeuOS在民爆生产厂区和北京运维中心配置... 3 1.1         ...

  6. (二)asyncio的简单使用,python异步高效处理数据,asyncio.get_event_loop(),loop.run_until_complete(main()),loop.close()

    Asyncio 是一个基于事件循环的异步I/O框架,它提供了高效的协程实现,能够轻松地编写高并发的Python程序.Asyncio 在 Python 3.4 中首次引入,它的核心是事件循环(Event ...

  7. easyx的使用 鼠标交互(3.1)

    本文学习于B站,进行借鉴学习记录: 视频链接:鼠标操作(新版)_哔哩哔哩_bilibili 初始化调用文件头不再使用#include<graphics.h>,选择调用#include< ...

  8. 力扣41(java)-缺失的第一个正数(困难)

    题目: 给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数. 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案. 示例 1: 输入:nums = [1,2,0 ...

  9. 牛客网-SQL专项训练18

    ①在下列sql语句错误的是?B 解析: 在sql中若要取得NULL,则必须通过IS NULL或者IS NOT NULL进行获取,无法直接使用等号. 一个等号(=)表示把1赋值给变量啊 ==:称为等值符 ...

  10. 转载 | 如何把 thinkphp5 的项目迁移到阿里云函数计算来应对流量洪峰?

    简介: 函数计算评测局的优秀征文! 如何把thinkphp5的项目迁移到阿里云函数计算来应对流量洪峰? 1. 为什么要迁移到阿里云函数? 我的项目是一个节日礼品领取项目,过节的时候会有短时间的流量洪峰 ...