大家好,欢迎来到IT知识分享网。
最近学习了kotlin的flow,感觉和RxJava很像 于是就利用它来封装网络请求。再之前的文章中我也封装过网络请求Android Kotlin Flow + 协程 + Retrofit + MVVM优雅的实现网络请求(简洁!!!),但是使用了flow 发现更简单。
封装的部分部分,很简单
suspend fun <T> requestFow( showLoading: Boolean = true, request: suspend ApiInterface.() -> BaseResponse<T>? ):Flow<BaseResponse<T>> {
if (showLoading) {
showLoading()
}
return flow {
val response = request(Api) ?: throw IllegalArgumentException("数据非法,获取响应数据为空")
if (response.errorCode != 0) {
throw ApiException(response.errorCode, response.errorMsg ?: "")
}
emit(response)
}.flowOn(Dispatchers.IO)
.onCompletion {
closeLoading()
}
}
IT知识分享网
就这么简单 就全部完成封装了
Api:就是Retrofit的ApiInterface对象
emit: 就是把网络请求的结果回调出去
flowOn:指定运行的线程 主要是flowOn 代码前面的线程
onCompletion:就是请求结束的回调,包括成功和失败 这里关闭了请求对话框
然后调用collect方法获取emit回调出的结果 就是网络请求的结果
IT知识分享网fun requestFlowData(){
viewModelScope.launch {
requestFow{
getListProject();
}.catch { cause ->
run {
Log.e("requestFow","==requestFow==cause==vm==>${cause}")
when (cause) {
is ApiException->{
}
is IOException->{
}
else->{ }
}
}
}.collect {
responseTextFlow.set(it.data.toString())
}
}
}
requestFlowData方法就是调用网络请求,这个是再Android中的viewmodel中调用的
因为方法调用再viewModelScope.launch 中 所以catch方法和collect方法 还有onCompletion方法 都是主线程中
requestFlow:就是封装的网络请求方法
catch: 捕获的是所有的异常,包括自定义的异常,这里我抛出了一个自定义的Api异常
collect:就是获取我们想要的数据
好了 一个网络请求就封装完毕了 就这么简洁
不过还有一个问题,就是捕获异常的问题,上面封装再调用的时候是每次都要加catch方法,如果不加则出现错误就会崩溃,比如IO异常,Api异常等。既然每次都要加的话,那我就把catch方法放在封装的内部调用了,就再onComplete方法后面加上catch,当然也可以onComplete方法前面加上,不同位置调用会不一样的效果 具体请看Android Kotlin Flow + 协程 + Retrofit + MVVM优雅的实现网络请求(简洁!!!)
当我加完之后,发现再调用的时候我用catch方法单独获取异常,发现单独获取异常的catch方法不执行了,看来catch只捕获一次异常,后面的方法就不会调用了。所以只能再catch和onComplete方法之前获取了,而且发现onComplete方法里面也能获取到异常
后来我想到了这个方法,封装的部分还是封装到onComplete,并且在onComplete方法内增加了对异常默认处理,就是简单的土司,可以二次加工异常再抛出去
suspend fun <T> requestFow( showLoading: Boolean = true, request: suspend ApiInterface.() -> BaseResponse<T>? ): Flow<BaseResponse<T>> {
if (showLoading) {
showLoading()
}
return flow {
val response = request(Api) ?: throw IllegalArgumentException("数据非法,获取响应数据为空")
if (response.errorCode != 0) {
throw ApiException(response.errorCode, response.errorMsg ?: "")
}
emit(response)
}.flowOn(Dispatchers.IO)
.onCompletion { cause ->
run {
closeLoading()
Log.e("requestFow", "==onCompletion==cause==>${cause}")
cause?.let {
toast(it.message?:"")
// throw it //可以对异常二次加工 然后抛出去
}
}
}
}
那这时候要捕获异常,难道又要每次调用的时候加catch方法?答案:当然不是!
这里我对collect方法下手,因为collect是每次必须调用的,你不调用你都获取不到数据,
既然它也是每次调用,那就把collect和catch方法放在一起,于是定义了一个这样的方法
IT知识分享网suspend fun <T> Flow<T>.next(bloc: suspend T.() -> Unit): Unit = catch { }.collect { bloc(it)}
next方法,只要调用了next方法就代表捕获异常和回调数据,这样有异常的化那next方法中的catch方法就已经捕获了,那要获取捕获的异常怎么办,其实就是还是用flow的catch捕获就行了,因为这时候catch是再next方法前面调用的会最先捕获到异常。调用的时候只是collect变成了next方法,变成如下这样了
requestFow() {
getListProject()
}.catch {
cause -> Log.e("requestFow", "==catch=========>${cause}")
}. next{
Log.e("requestFow", "==collect=---------------=next==>${this}")
responseTextFlow.set(data.toString())
}
这样就顺畅多了,如果需要异常单独处理就调用的时候加catch ,不需要就不调用 ,这时候出异常了走next方法的catch。然后异常的默认统一处理再onComplete方法里面
详细的就不多说了 看demo吧,github地址:
github.com/wangxiongta…
欢迎提供意见建议
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/13309.html