为了方便读者理解,我们用玩安卓的api来辅助说明,首先玩安卓的api接口返回值全是一个模板(大部分公司都类似),用实体类表示如下:
/** * 带壳的相应bean * @param T data实体类 * @property data T 报文中对应data的部分 * @property errorCode Int 报文中对应errorCode的部分 * @property errorMsg String 报文中对应errorMsg的部分 * @constructor */ data class WanBeanWrapper<T>( val data: T, val errorCode: Int = -1, val errorMsg: String = "" ) { companion object { const val SUCCESS_CODE = 0 const val LOGIN_ERROR_CODE = -1001 } /** * 请求是否成功 * @return Boolean true:成功 */ fun isSuccessful(): Boolean { return errorCode == SUCCESS_CODE } /** * 登陆失败 * @return Boolean true:登陆失败 */ fun isLoginError(): Boolean { return errorCode == LOGIN_ERROR_CODE } }
对于全局拦截器来说,只需要关注到这个壳的就够了,假设我们需要实现一个逻辑:当errorCode不等于SUCCESS_CODE的时候,我们需要将Success类型的networkResult转成Error类型的NetworkResult。
来看看笔者在项目中实现的一个拦截器:
class WanGlobalNetworkResultInterceptor @Inject constructor() : GlobalNetworkResultInterceptor { override fun <T> onIntercept(networkResult: NetworkResult<T>): NetworkResult<T> { return if ( //只有成功才转换 networkResult is Success && //只转换这种类型的Bean networkResult.responseBody is WanBeanWrapper<*> ) { //类型强转 val wanBeanWrapper = (networkResult.responseBody as WanBeanWrapper<*>) //如果不成功 if (!wanBeanWrapper.isSuccessful()) { return MsgException(wanBeanWrapper.errorMsg).toExceptionResult() } networkResult } else { networkResult } } }
可以看出完成了NetworkResult类型的转换,一开始是一个Success类型的,然后通过校验报文中的errorCode来发现后台给我们报错了,于是我们基于MsgException(只是一个简单的IoException的子类,笔者用来在okhttp的拦截其中报一些自定义的错误,你可以使用你想要的任意异常来封装ExceptionResult)来生成一个新ExceptionResult。这样,原本会走向成功的逻辑变成走向了错误的逻辑,调用者无需在每一次网络请求成功之后都手动判断errorCode是否正常!
让我们回到第一章的代码,进行少部分的修改。
//扩展方法新增一个参数 fun <T> Response<T>.toNetworkResult(interceptor: GlobalNetworkResultInterceptor): NetworkResult<T> = interceptor.onIntercept( try { if (isSuccessful) { toSuccessResult() } else { toServerErrorResult() } } catch (t: Throwable) { t.toExceptionResult() } ) //代理类 internal class ApexResponseCallDelegate<T>( private val proxyCall: Call<T>, //新增参数,传入全局拦截器 private val interceptor: GlobalNetworkResultInterceptor ) : Call<NetworkResult<T>> { override fun enqueue(callback: Callback<NetworkResult<T>>) = proxyCall.enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { callback.onResponse( this@ApexResponseCallDelegate, Response.success( //将参数传入到这里使用 response.toNetworkResult(interceptor) ) ) } //省略部分代码 })
这样就可以低成本的对原本的代码进行修改,全局返回结果的拦截修改就完成了!
感谢你看到这里,这个简单的系列就到此结束了,如果你有更多疑问可以在评论区给笔者留言,想看源码也可以去笔者的开源项目中找到相关的代码(搜索类名即可,部分类名可能会发生改变)。