安卓开发封装处理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发送请求
安卓开发封装处理Retrofit协程请求中的异常的更多相关文章
- python自动化开发学习 进程, 线程, 协程
python自动化开发学习 进程, 线程, 协程 前言 在过去单核CPU也可以执行多任务,操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换任务2,任务2执行0.01秒,在切换到任务3,这 ...
- python 全栈开发,Day43(引子,协程介绍,Greenlet模块,Gevent模块,Gevent之同步与异步)
昨日内容回顾 I/O模型,面试会问到I/O操作,不占用CPU.它内部有一个专门的处理I/O模块.print和写log 属于I/O操作,它不占用CPU 线程GIL保证一个进程中的多个线程在同一时刻只有一 ...
- 封装你的协程Unity TaskManager
unity5提供了协程,不过用起来很蛋疼,当然如果是unity2017 你就可以用async await了 提供一个TaskManager来封装协程(github https://github.co ...
- Python协程(中)
协程嵌套 使用async可以定义协程,协程用于耗时的io操作,我们也可以封装更多的io操作过程,这样就实现了嵌套的协程,即一个协程中await了另外一个协程,如此连接起来. import asynci ...
- 【Golang】如何统一处理HTTP请求中的异常捕获
最近写GOLANG项目,不使用框架,路由选择httprouter 现在想实现一个需求:在不修改httprouter源码的前提下,对所有注册的路由handle进行异常捕获. 大家都知道golang使用p ...
- [日常] 使用TCPDUMP和Ethereal抓包分析HTTP请求中的异常情况
在测试功能的过程中,出现这样一种现象.前端js发起ajax请求后,在浏览器的审查元素网络状态中可以看到status为pending,等15秒以后js会把当前超时的请求取消掉,变成了红色的cancel. ...
- Python全栈开发-Day10-进程/协程/异步IO/IO多路复用
本节内容 多进程multiprocessing 进程间的通讯 协程 论事件驱动与异步IO Select\Poll\Epoll——IO多路复用 1.多进程multiprocessing Python ...
- RxHttp ,比Retrofit 更优雅的协程体验
1.前言 Hello,各位小伙伴,又见面了,回首过去,RxHttp 就要迎来一周年生日了(19年4月推出),这一年,走过来真心....真心不容易,代码维护.写文章.写文档等等,经常都是干到零点之后,也 ...
- Python开发【第九章】:线程、进程和协程
一.线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务 1.t ...
- Python开发基础-Day32 进程间通信、进程池、协程
进程间通信 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的. 进程队列queue 不同于线程queue,进程 ...
随机推荐
- 记录C++,读文件返回base64数据
读文件返回base64函数: void CZZUser::hidFileToBase(const char* filePath) { // 文件 转 base64 // 计算文件长度 unsigned ...
- Jenkins首次启动慢
场景描述启动Jenkins后,打开网站,发现一直卡在这个启动页面,慢,很慢,非常慢 解决方法 进入Jenkins的安装目录,找到"hudson.model.UpdateCenter.xml& ...
- HarmonyOS自动化测试框架—Hypium
原文:https://mp.weixin.qq.com/s/nb5txfDcmGn_VZJXRPEYUQ,点击链接查看更多技术内容. 应用开发过程中,要确保应用的功能和界面能满足预期,往往需要通过测试 ...
- 树模型-LightGBM-从三个层面改进xgb
LightGBM lightGBM总结
- java 读取文本文件超简单的方法
答案是:Scanner读取,初学者大部分都用过这货,然而这货还有这样两个构造方法: public Scanner(File source); public Scanner(InputStream st ...
- argparse命令行参数的使用
import argparse def main(): #设置一些参数 parser = argparse.ArgumentParser() parser.add_argument('--device ...
- vue 商品sku添加,笛卡尔算法,商品添加。动态生成table,table添加值后 再生成的table 不改变table之前输入的值
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 暑期集训 Day10 —— 模拟赛复盘
${\color{Green} \mathrm{Problem\ 0 :water }} $ 题如其名,可以用单调队列做,但是数据范围直接暴力枚举每一高度就行. 最不会打错的,还是暴力,所以用暴力. ...
- 【Serverless实战】B站每日自动签到&&传统单节点网站的Serverless上云
简介: Serverless好哇!这里将针对个人与生产两个应用方向的测评 使用Serverless实现自动获取每日B站的经验值,让你更快冲到LV6! 你的业务站点还是一台服务器All in One吗? ...
- 基于Delta lake、Hudi格式的湖仓一体方案
简介: Delta Lake 和 Hudi 是流行的开放格式的存储层,为数据湖同时提供流式和批处理的操作,这允许我们在数据湖上直接运行 BI 等应用,让数据分析师可以即时查询新的实时数据,从而对您的 ...