【Jetpack 篇】协程,腾讯 T3 团队整理
STATE_UNKNOWN//未知}
将 DataState 添加到 BaseResp 中,
/**
json 返回的基本类型*/class BaseResp<T>{var errorCode = -1var errorMsg: String? = nullvar data: T? = nullprivate setvar dataState: DataState? = nullvar error: Throwable? = nullval isSuccess: Booleanget() = errorCode == 0}
那 StateLiveData 该如何使用呢?
我们都知道数据请求会有不同的结果,成功,异常或者数据为 null,那么就可以利用不同的结果,将相应的状态设置在 BaseResp 的 DataState 中。直接进入到数据请求 Repository 层,对上篇异常处理做了改进。
open class BaseRepository {/**
repo 请求数据的公共方法,
在不同状态下先设置 baseResp.dataState 的值,最后将 dataState 的状态通知给 UI/suspend fun <T : Any> executeResp(block: suspend () -> BaseResp<T>,stateLiveData: StateLiveData<T>) {var baseResp = BaseResp<T>()try {baseResp.dataState = DataState.STATE_LOADING//开始请求数据 val invoke = block.invoke()//将结果复制给 baseRespbaseResp = invokeif (baseResp.errorCode == 0) {//请求成功,判断数据是否为空,//因为数据有多种类型,需要自己设置类型进行判断 if (baseResp.data == null || baseResp.data is List<> && (baseResp.data as List<*>).size == 0) {//TODO: 数据为空,结构变化时需要修改判空条件 baseResp.dataState = DataState.STATE_EMPTY} else {//请求成功并且数据为空的情况下,为 STATE_SUCCESSbaseResp.dataState = DataState.STATE_SUCCESS}
} else {//服务器请求错误 baseResp.dataState = DataState.STATE_FAILED}} catch (e: Exception) {//非后台返回错误,捕获到的异常 baseResp.dataState = DataState.STATE_ERRORbaseResp.error = e} finally {stateLiveData.postValue(baseResp)}}}
executeResp()
为数据请求的公共方法,该方法传入了两个参数,第一个是将数据请求函数当作参数,第二个就是上面新建的StateLiveData
。
方法一开始就新建了一个 BaseResp()对象,将DataState.STATE_LOADING
状态设置给 BaseResp 的 dataState,接着开始对数据请求进行异常处理(具体可查看上一篇),如果 code=0 表示接口请求成功,否则表示接口请求成功,服务器返回错误。在 code=0 时,对返回数据进行判空处理,因为数据有多种类型,这里需要自己设置类型进行判断,为空就将状态设置为DataState.STATE_EMPTY
,否则为
DataState.STATE_SUCCESS
。如果抛出异常,则将状态设置为DataState.STATE_ERROR
,在请求结束后,利用stateLiveData
将带有状态的 baseResp 分发给 UI。
到这里,请求状态都设置完成,接下来只需要根据不同状态,开始进行界面切换处理。
三、结合 LoadSir 界面切换
LoadSir是一个加载反馈页管理框架,状态页自动切换,具体使用在这里就不描述了,需要的可移步github查看。
LiveData 接收数据变化时,UI 会先注册一个接收事件的观察者,接收到请求的数据后就进行 UI 更新,第二节里将不同状态也添加到了数据中,要想对状态也进行监听的话,就需要对 Observer 进行状态处理。
/**
LiveData Observer 的一个类,
主要结合 LoadSir,根据 BaseResp 里面的 State 分别加载不同的 UI,如 Loading,Error
同时重写 onChanged 回调,分为 onDataChange,onDataEmpty,onError,
开发者可以在 UI 层,每个接口请求时,直接创建 IStateObserver,重写相应 callback。*/abstract class IStateObserver<T>(view: View?) : Observer<BaseResp<T>>, Callback.OnReloadListener {private var mLoadService: LoadService<Any>? = null
init {if (view != null) {mLoadService = LoadSir.getDefault().register(view, this,Convertor<BaseResp<T>> { t ->var resultCode: Class<out Callback> = SuccessCallback::class.java
when (t?.dataState) {
//数据刚开始请求,loadingDataState.STATE_CREATE, DataState.STATE_LOADING -> resultCode =LoadingCallback::class.java//请求成功 DataState.STATE_SUCC
ESS -> resultCode = SuccessCallback::class.java//数据为空 DataState.STATE_EMPTY -> resultCode =EmptyCallback::class.javaDataState.STATE_FAILED ,DataState.STATE_ERROR -> {val error: Throwable? = t.erroronError(error)//可以根据不同的错误类型,设置错误界面时的 UIif (error is HttpException) {//网络错误} else if (error is ConnectException) {//无网络连接} else if (error is InterruptedIOException) {//连接超时} else if (error is JsonParseException|| error is JSONException|| error is ParseException) {//解析错误} else {//未知错误}resultCode = ErrorCallback::class.java}DataState.STATE_COMPLETED, DataState.STATE_UNKNOWN -> {}else -> {}}Log.d(TAG, "resultCode :$resultCode ")resultCode})}
}
override fun onChanged(t: BaseResp<T>) {Log.d(TAG, "onChanged: ${t.dataState}")
when (t.dataState) {DataState.STATE_SUCCESS -> {//请求成功,数据不为 nullonDataChange(t.data)}
DataState.STATE_EMPTY -> {//数据为空 onDataEmpty()}
DataState.STATE_FAILED,DataState.STATE_ERROR->{//请求错误 t.error?.let { onError(it) }}else -> { }}
//加载不同状态界面 Log.d(TAG, "onChanged: mLoadService $mLoadService")
mLoadService?.showWithConvertor(t)
}
/**
请求数据且数据不为空*/open fun onDataChange(data: T?) {
}
/**
请求成功,但数据为空*/open fun onDataEmpty() {
}
/**
请求错误*/open fun onError(e: Throwable?) {
}}
IStateObserver
是Observer
接口的实现类,参数传入了一个 View,而这个 View 就是你所要替换的界面,这也就是同个界面,不同模块显示异常不同的关键所在。因为是结合 Loadsir,首先需要初始化 LoadService,再者通过 dataState 的状态值,设置不同的 Callback,例如 Loading 时,设置为LoadingCallback
,Error 时,设置为ErrorCallback
,Empty 时设置为EmptyCallback
,设置完成后,在 onChanged 回调中统一调用showWithConvertor
,也就是切换界面的操作。
而在 onChange 回调中,同样根据状态值,分别分发onDataChange
,onDataEmpty
,onError
的通知。
到这里,完成了不同状态界面切换和状态通知的分发工作。
四、如何使用
评论