当前位置:网站首页>【Android Kotlin协程】利用CoroutineContext实现网络请求失败后重试逻辑
【Android Kotlin协程】利用CoroutineContext实现网络请求失败后重试逻辑
2022-07-06 22:22:00 【程序员小何SS】
前言
在Android开发中有一个典型场景:网络请求失败后重试:一般的逻辑是弹出一个Dialog提醒用户“网络请求失败”,并提供重试的按钮。
如果当前页面只有一个网络请求,那么逻辑就很简单了:只需要再调用一下发起这个网络请求的方法就可以了。而当一个页面有多个网络请求时,我常用的办法为失败回调加状态,根据不同的状态调用不同的方法。但是这个方法不免有些繁琐,也有点不安全。首先,你要额外的增加状态,并将它传来传去。有些情况下,你甚至还需要重新初始化网络请求参数。更要命的是:你还要管理这个状态,一旦管理不善,就会导致调用了不该调用的方法,引入严重的BUG。
直到有一天我看到CoroutineExceptionHandler
,灵光突现——可以使用协程上下文来保存将来可能需要重试的网络请求和Request数据,这样就能解决上面的问题了。
由于我所开发的大多数项目都是采用ViewModel实现网络请求逻辑和UI层的解耦,而网络请求基本上是采用Coroutine+Retrofit的方式实现的,基本上都是使用viewModelScope。
viewModelScope.launch() {
request()
}
viewModelScope本质上是一个ViewModel的扩展函数,利用它可以便捷的在ViewModel创建协程,具体的代码就不展开了。默认情况下,它的CoroutineContext由Job和CoroutineDispatcher组成。而协程的上下文本质上就是一个实现了key-value访问的方式的链表结构。我们可以通过继承AbstractCoroutineContextElement
的方式实现自定义的CoroutineContext上下文:
class RetryCallback(val callback: () -> Unit) : AbstractCoroutineContextElement(RetryCallback) {
companion object Key : CoroutineContext.Key<RetryCallback>
}
紧接着,当网络请求发生异常时借助CoroutineExceptionHandler
获取到我们需要重新执行的操作:
val coroutineExceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
val callback = coroutineContext[RetryCallback]
?.callback
}
紧接着,要将coroutineExceptionHandler添加到发起网络请求的协程上下文里:
viewModelScope.launch(exceptionHandler
+ RetryCallback { request() }) {
request()
}
此时,只要在发起网络请求的页面里获取到callback
,并在点击重试按钮的时候调用它,就能实现重试的逻辑。
进一步对它进行封装并增加失败后自动重试逻辑,创建供ViewModel使用的接口,用来处理网络请求错误的后续逻辑:
interface ViewModelFailed {
/**
* @param throwable:异常信息
* @param callback:需要重试的函数
* */
fun requestFailed(throwable: Throwable, callback: () -> Unit)
}
为它创建扩展函数,用来创建CoroutineExceptionHandler
和RetryCallback
上下文实例:
/**
* @param autoReTry:是否自动重试
* @param callback:需要重试的函数
* */
fun ViewModelFailed.initRetry(autoReTry: Boolean = false, callback: () -> Unit) =
CoroutineExceptionHandler { coroutineContext, throwable ->
val retryCallBack = {
coroutineContext[RetryCallback]
?.callback?.invoke()
}
if (autoReTry) {
//自动开始重试逻辑
onRetry()
retryCallBack.invoke()
} else {
//不自动开始重试,后续操作交给用户决定
requestFailed(throwable) {
retryCallBack
}
}
} + RetryCallback(callback)
ViewModel需要实现ViewModelFailed接口,并在发起网络请求的协程中调用initRetry
方法添加异常处理上下文:
class MainViewViewModel : ViewModel(), ViewModelFailed {
val liveData: MutableLiveData<BaseData> = MutableLiveData()
/**
* @param num:用来演示Request请求数据
* @param repeat:失败后自动重试的次数
* */
fun request(num: Int, repeat: Int = 0) {
liveData.value = BaseData.loading()
viewModelScope.launch(initRetry(repeat > 0) {
request(num,repeat - 1)
}) {
liveData.value = BaseData.success(simulateHttp(num))
}
}
private suspend fun simulateHttp(num: Int) = withContext(Dispatchers.IO) {
//模拟网络请求
...
}
override fun requestFailed(throwable: Throwable, callback: () -> Unit) {
//处理失败逻辑
dialog()
//重试
callback.invoke()
}
override fun onRetry() {
}
}
最后
Android学习是一条漫长的道路,我们要学习的东西不仅仅只有表面的 技术,还要深入底层,弄明白下面的 原理,只有这样,我们才能够提高自己的竞争力,在当今这个竞争激烈的世界里立足。
人生不可能一帆风顺,有高峰自然有低谷,要相信,那些打不倒我们的,终将使我们更强大,要做自己的摆渡人。
我把自己这段时间整理的Android最重要最热门的学习方向资料放在了下方二维码中,里面还有不同方向的自学编程路线、面试题集合/面经、及系列技术文章等。**
资源持续更新中,欢迎大家一起学习和探讨。
边栏推荐
- MySQL split method usage
- Complimentary tickets quick grab | industry bigwigs talk about the quality and efficiency of software qecon conference is coming
- JS also exports Excel
- Gavin teacher's perception of transformer live class - rasa project actual combat e-commerce retail customer service intelligent business dialogue robot microservice code analysis and dialogue experim
- Oracle - views and sequences
- Data security -- 12 -- Analysis of privacy protection
- System framework of PureMVC
- The request request is encapsulated in uni app, which is easy to understand
- 过气光刻机也不能卖给中国!美国无理施压荷兰ASML,国产芯片再遭打压
- 深耕开发者生态,加速AI产业创新发展 英特尔携众多合作伙伴共聚
猜你喜欢
图灵诞辰110周年,智能机器预言成真了吗?
Local tool [Navicat] connects to remote [MySQL] operation
Vscode 如何使用内置浏览器?
Oracle -- 视图与序列
[hand torn STL] list
九章云极DataCanvas公司摘获「第五届数字金融创新大赛」最高荣誉!
How to package the parsed Excel data into objects and write this object set into the database?
Analyse approfondie de kubebuilder
Basic idea of counting and sorting
C # use Siemens S7 protocol to read and write PLC DB block
随机推荐
Camera calibration (I): robot hand eye calibration
Advertising attribution: how to measure the value of buying volume?
Is there any way to bookmark the code in the visual studio project- Is there a way to bookmark code in a Visual Studio project?
案例大赏:英特尔携众多合作伙伴推动多领域AI产业创新发展
Data security -- 12 -- Analysis of privacy protection
MySQL forgot how to change the password
NTU notes 6422quiz review (1-3 sections)
软件测试之网站测试如何进行?测试小攻略走起!
Introduction to the PureMVC series
Vscode 如何使用内置浏览器?
Comment les tests de logiciels sont - ils effectués sur le site Web? Testez la stratégie!
Jetson nano configures pytorch deep learning environment / / to be improved
A simple and beautiful regression table is produced in one line of code~
If you ask me about R code debugging, I will tell you head, STR, help
一度辍学的数学差生,获得今年菲尔兹奖
Thesis landing strategy | how to get started quickly in academic thesis writing
Easycvr cannot be played using webrtc. How to solve it?
What about the collapse of win11 playing pubg? Solution to win11 Jedi survival crash
AttributeError: module ‘torch._C‘ has no attribute ‘_cuda_setDevice‘
抖音或将推出独立种草社区平台:会不会成为第二个小红书