Android Kotlin Flow + 协程 + Retrofit + MVVM优雅的实现网络请求(简洁!!!)

最近学习了kotlin的flow,感觉和RxJava很像 于是就利用它来封装网络请求。再之前的文章中我也封装过网络请求juejin.cn/post/692263…,但是使用了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).catch {  
   cause -> run { 
        Log.e("requestFow", "==requestFow==cause==>${Thread.currentThread().name}")     
        toast(cause.message ?: "null")       
        throw cause// 这里再重新把捕获的异常再次抛出,调用的时候如果有必要可以再次catch 获取异常  
    }} 
.onCompletion {  
  closeLoading()   
 }
}
复制代码

就这么简单 就全部完成封装了

Api:就是Retrofit的ApiInterface对象 

emit: 就是把网络请求的结果回调出去

flowOn:指定运行的线程 主要是flowOn 代码前面的线程

catch: 捕获的是所有的异常,包括自定义的Api异常,这里 我把异常 默认处理 为土司然后 我又把异常 抛出去,再调用的时候会捕获到,同样使用catch捕获

onCompletion:就是请求结束的回调,包括成功和失败 这里关闭了请求对话框

然后调用collect方法获取emit回调出的结果 就是网络请求的结果

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:就是获取抛出的异常,不获取 可不写

collect:就是获取我们想要的数据

好了 一个网络请求就封装完毕了 就这么简洁

嗯 这里 我觉得catch和collect还是写的麻烦 于是 封装一下

fun <T> Flow<T>.catch(bloc: Throwable.() -> Unit) = catch { cause -> bloc(cause) }

suspend fun <T> Flow<T>.next(bloc: suspend T.() -> Unit): Unit = collect { bloc(it) }
复制代码

这样上面的网络请求的封装就是

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).catch {  
  Log.e("requestFow","==requestFow==cause==>${Thread.currentThread().name}")  
  toast(message ?: "null")   
 throw this// 这里再重新把捕获的异常再次抛出,调用的时候如果有必要可以再次catch 获取异常
}.onCompletion {  
  closeLoading()   
 }
}
复制代码

调用的时候就是这样了

fun requestFlowData(){ 
   viewModelScope.launch {  
      requestFow{     
       getListProject();     
       }.catch {         
                  
            
            when (this) {      
              is ApiException->{      
              }                 
              is IOException->{     
                }         
              else->{    }            
    
               } 
           
    }.next{   
         responseTextFlow.set(data.toString())  
      }   
 }
}
复制代码

详细的就不多说了 看demo吧,github地址:

github.com/wangxiongta…

欢迎提供意见建议

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享