三:重写CallAdapter
所谓的CallAdapter,就是对原来的Call进行适配,对方法的返回值进行扩展,废话不多说,直接看代码。
internal class ApexResponseCallDelegate<T>(private val proxyCall: Call<T>) : Call<NetworkResult<T>> { override fun enqueue(callback: Callback<NetworkResult<T>>) = proxyCall.enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { //得到响应,将被代理的Call的响应包装成NetworkResult后返回给代理者 callback.onResponse( this@ApexResponseCallDelegate, Response.success( //将Retrofit中的Response转成NetworkResult response.toNetworkResult() ) ) } override fun onFailure(call: Call<T>, t: Throwable) { //失败了,将被代理的Call的异常包装成NetworkResult后返回给代理者 callback.onResponse( this@ApexResponseCallDelegate, //将Exception转成NetworkResult Response.success(t.toExceptionResult()) ) } }) //下面都是不变的代理方法 override fun isExecuted(): Boolean = proxyCall.isExecuted override fun cancel() = proxyCall.cancel() override fun isCanceled(): Boolean = proxyCall.isCanceled override fun request(): Request = proxyCall.request() override fun timeout(): Timeout = proxyCall.timeout() override fun clone(): Call<NetworkResult<T>> = ApexResponseCallDelegate(proxyCall.clone()) override fun execute(): Response<NetworkResult<T>> = throw NotImplementedError() } //相关的扩展方法如下: fun <T> Response<T>.toNetworkResult(): NetworkResult<T> = try { if (isSuccessful) { toSuccessResult() } else { toServerErrorResult() } } catch (t: Throwable) { t.toExceptionResult() } fun <T> Response<T>.toSuccessResult(): Success<T> { return Success(this) } fun <T> Response<T>.toServerErrorResult(): ServerError<T> { return ServerError(this) } fun <T> Throwable.toExceptionResult(): NetworkResult.Failure.Exception<T> { return NetworkResult.Failure.Exception(this) }
代码特别多,有一点需要注意的是,无论被代理的Call的网络请求是成功还是失败,最终返回的都是Response.success。这一点确保了我们定义的方法,无论如何都不会对外抛出异常,无论网络请求成功还是失败,都会当做某种“成功”来处理,你可以理解成“网络请求结束”,原本网络请求失败的结果,已经被包裹在NetworkResult里面了。
下面是CallAdapter本体,以及附属的工厂类
class ApexCallAdapterFactory @Inject constructor() : CallAdapter.Factory() { class ApexCallAdapter constructor( private val resultType: Type ) : CallAdapter<Type, Call<NetworkResult<Type>>> { override fun responseType() = resultType override fun adapt(call: Call<Type>): Call<NetworkResult<Type>> = ApexResponseCallDelegate(call) } override fun get( returnType: Type, annotations: Array<out Annotation>, retrofit: Retrofit ): ApexCallAdapter? = when (getRawType(returnType)) { Call::class.java -> { //判断方法返回值 val callType = getParameterUpperBound(0, returnType as ParameterizedType) //只有返回值是NetworkResult的才会使用本Adapter when (getRawType(callType)) { NetworkResult::class.java -> { val resultType = getParameterUpperBound(0, callType as ParameterizedType) ApexCallAdapter(resultType) } else -> null } } else -> null } }
代码也挺多的,本质上是定义了一个Adapter以及工厂类,工厂类的get用于判断当前的方法是否适合使用工厂类对应的Adapter(因为Retrofit允许同时存在多个Adapter以应对不同的返回值,因此我们需要判断方法返回值是否是NetworkResult)
最后的最后,在Retrofit的构造方法中,添加我们自己实现的Adapter工厂类即可,Retrofit就会识别出我们定义的NetworkResult并正确的返回结果啦,记得要把方法改成suspend。
Retrofit.Builder() .baseUrl(baseUrl) .addCallAdapterFactory(callAdapterFactory) .client(okHttpClient) .build() //请求结果 val result=friendService.requestFriend(FriendService.FriendRequestParam(nextPage)) when(result){ //判断类型 is Success->{} is Exception->{} }
每次都要手写when代码着实有些蛋疼,让我们给NetworkResult扩充一些方法,自动帮我们完成判断的逻辑
/** * 网络请求成功时操作 */ inline fun <reified T> NetworkResult<T>.ifSuccess(action: (NetworkResult.Success<T>) -> Unit): NetworkResult<T> { if (this is NetworkResult.Success) action(this) return this } /** * 网络请求中,服务器已响应但HTTP协议出现错误时(例如404,502)操作 */ inline fun <reified T> NetworkResult<T>.ifServerError(action: (NetworkResult.Failure.ServerError<T>) -> Unit): NetworkResult<T> { if (this is NetworkResult.Failure.ServerError) action(this) return this } /** * 网络请求中,出现异常时(例如解析JSON异常,超时异常,连接网络失败异常等)操作 */ inline fun <reified T> NetworkResult<T>.ifException(action: (NetworkResult.Failure.Exception<T>) -> Unit): NetworkResult<T> { if (this is NetworkResult.Failure.Exception) action(this) return this } /** * 网络请求失败(包括[ifServerError]和[ifException]两种情况) */ inline fun <reified T> NetworkResult<T>.ifFailure(action: (errorMsg: String) -> Unit): NetworkResult<T> { ifServerError { //errorBodyString()方法在下篇文章中会提到 action(it.errorBodyString()) }.ifException { //exceptionMessage()方法在下篇文章中会提到 action(it.exceptionMessage()) } return this }
接下来使用起来就是这样了(切记在协程作用域中调用本方法哦,因为是suspend方法)
searchRepository.search(SearchService.SearchRequestBody(key)).ifSuccess { //成功时 }.ifFailure { //失败时 }.ifServerError { //服务器内部错误时 }.ifException { //发生了异常时 }
文章到这里已经结束了,第一篇中我们实现了一套CallAdapter,
这套adpter的意义是消除了原来的回调式代码,让回调风格代码“拉平”了,
变成了我们熟悉的同步代码,下一篇我将解决几个项目中遇到的常见问题。