前言
在App中,对于网络请求状态一般性的就分为加载中、请求错误、请求成功、请求成功但数据为null。为了用户体验,不同的状态需要对用户展示不同的界面,例如网络异常的提醒,点击重新请求等。
之前项目一直都是以Retrofit+RxJava+OkHttp为网络请求框架,RxJava已经很好的封装了不同的请求状态,onSubscribe、onNext、onError等,只需要在不同的回调中做出相应的动作就ok了。
RxJava很好用,但随着新技术的出现,RxJava的可替代性也就越高。Kotlin的协程就是这么一个存在。
本文是以Jetpack架构为基础,协程+Retrofit+Okhttp为网络请求框架,对不同的请求状态(loading,error,empty等)做了封装,让开发者不用再去关心哪里需要loading,哪里需要展示error提示。
同时,在封装的过程中,Jetpack和协程的使用也存在着几个坑,本文也将一一描述。
协程的基本使用
API:https://www.wanandroid.com/project/tree/json 来自鸿洋大大的wanandroid
如果需要使用协程,则添加依赖
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
}
在Retrofit2.6.0前,我们使用协程,api请求后返回的数据可以用Call或者Defeerd包裹处理,2.6后,可以直接返回数据,只不过需要加上suspend的修饰,如下:
interface ProjectApi {
@GET("project/tree/json")
suspend fun loadProjectTree(): BaseResp<List<ProjectTree>>
}
因为使用的是Jetpack架构,所以将整个网络请求主要分为UI、ViewModel、Repository三层,以LiveData为媒介进行通信。
首先是Repository层进行网络请求,
class ProjectRepo{
private lateinit var mService: ProjectApi
init {
mService = RetrofitManager.initRetrofit().getService(ProjectApi::class.java)
}
suspend fun loadProjectTree(): List<ProjectTree> {
return mService.loadProjectTree()
}
}
利用Retrofit和OkHttp创建了一个apiService,内部细节在这里就先不展开,接着直接调用loadProjectTree()进行网络请求,将数据返回。loadProjectTree()用suspend关键字进行标记,Kotlin 利用此关键字强制从协程内调用函数。
接着ViewModel层,
class ProjectViewModel : ViewModel(){
//LiveData
val mProjectTreeLiveData = MutableLiveData<List<ProjectTree>>()
fun loadProjectTree() {
viewModelScope.launch(Dispatchers.IO) {
val data = mRepo.loadProjectTree()
mProjectTreeLiveData.postValue(data)
}
}
}
创建类ProjectViewModel并继承ViewModel,内部新建一个LiveData做UI通信使用,利用viewModelScope.launch(Dispatchers.IO)
创建一个新的协程,然后在 I/O 线程上执行网络请求,请求的数据利用LiveData通知给UI。
这里提到了viewModelScope.launch(Dispatchers.IO)
,viewModelScope
是一个协程的作用域,ViewModel KTX 扩展中已经将此作用域封装好,直接使用就可以。Dispatchers.IO
表示此协程在 I/O线程上执行,而launch则是创建一个新的协程。
最后是UI层,
class ProjectFragment : Fragment {
override fun initData() {
//请求数据,调用loadProjectTree
mViewModel?.loadProjectTree()
mViewModel?.mProjectTreeLiveData?.observe(this, Observer {
//更新UI
})
}
UI层开始调用ViewModel的请求方法执行网络请求,LiveData注册一个观察者,观察数据变化,并且更新UI。
到这里,网络请求的逻辑基本上通顺了。
在一切环境正常的情况下,上面的请求是可以的,但是app还存在网络不畅,异常,数据为null的情况,上述就不在满足要求了,接下来就开始对数据异常的情况进行处理。
网络请求异常处理
对于协程异常的处理,Android开发者的官网上也给出了答案(https://developer.android.google.cn/kotlin/coroutines?hl=zh-cn ) ,直接对网络请求进行一个try-catch
处理,发生异常了,直接在catch中做出相应动作就ok了,我们就来看看具体实现。
class ProjectViewModel : ViewModel(){
//LiveData
val mProjectTreeLiveData = MutableLiveData<List<ProjectTree>>()
fun loadProjectTree() {
viewModelScope.launch(Dispatchers.IO) {
try {
val data = mRepo.loadProjectTree()
mProjectTreeLiveData.postValue(data