转载请附原文链接:自定义Retrofit的Convert统一处理返回结果为Observable<T>
需求
最近公司开了一个新项目,在搭建项目的时候,我们希望将服务端返回列表数据直接与我们的 List 控件绑定,高度封装,方便使用,所以与服务端定义了请求返回数据格式,当一个页面含有列表 List 数据,第一次进入页面数据格式如下:
|
|
当我们对 list1 进行下拉刷新或者上拉加载更多的时候服务端返回数据格式如下:
|
|
对比这两次网络请求返回的数据,我们发现两次的数据跟节点的 data 层数据格式不一样!这就很蛋疼了,这样跟节点的 data 层就是对应两个 JavaBean 对象了,本来这个界面的数据我是只想通过一个网络请求搞定,但是由于服务端返回数据格式两次不一样,那么现在就不能通过一个网络请求接口搞定了,就得写出下面这样两个接口:
|
|
这样写起来是很蛋疼的,只要有 List 列表需要刷新或者加载更多的界面都需要这么写,简直难以接受!
解决方案
天真想法
想一下如果 Retrofit 支持下面这种泛型写法那是不是就可爱了:
|
|
即传入一个泛型,当我们调用的时候再传入具体类型,自己试了下,炸了,报错信息是,不能传入泛型 T ,这个问题在 Retrofit 项目下面也有人提过 issue ,JakeWharton 大神给出了否定回答,那么就死了这条心,想想这也是天真的想法,因为 Gson 在进行转换的时候你传入的是泛型 T 不是具体类型,而运行时 泛型 T 是擦除的,怎么能实现转换。
正确思路
现在我们想要调用接口返回的数据格式为 Observable<BaseBean<T>>
格式,但是 Retrofit 不支持,Retrofit 要求这个 T 必须是具体的 JavaBean 类型,但是我们最终想要的结果的是 T 类型,那么就想办法自己中转一层试试,思路就是让 Retrofit 返回统一格式为 Observable<BaseBean<String>>
类型,然后我们自己去把 Observable<BaseBean<String>>
转换为 Observable<BaseBean<T>>
类型,这样就达到我们在最终目的。
Converter.Factory 使用
原理
注意:要想去自定义 Converter.Factory 我们肯定是要先去弄懂他工作的原理了。
怎么让 Retrofit 返回 Observable<BaseBean<String>>
呢,当然是借助 Converter.Factory 转换器,功能很强大。下面代码我们应该很熟悉:
|
|
这里 ScalarsConverterFactory
和 GsonConverterFactory
这两个转换器一般我们都会在项目中添加,而且已经有裤子我们添加个依赖就可以用,ScalarsConverterFactory
是将服务端返回数据转为 String、Boolean、Byte 等类型,GsonConverterFactory
是将服务端返回数据利用 Gson 转换为我们指定对应的 JavaBean 对象,但是上面调用 addConverterFactory
一定要注意先后顺序,比如我们先调用 addConverterFactory(GsonResponseBodyConverter.create())
再调用 addConverterFactory(ScalarsConverterFactory.create())
这时你去调用如下接口:
|
|
那么程序就会崩溃!为什么呢?一起来看源码!
当我们调用 addConverterFactory
看看发生了什么。
|
|
其实就是将转换器 factory 对象加入到 retrofit 内部自己维护的一个 list 集合中。
那么是如何调用的呢?看下面代码就是处理网络请求返回结果:
|
|
上面代码就是在处理网络请求返回结果的时候去遍历存储转换器 factory 的 list 对象集合,只要返回的 converter 对象不为 null ,那么就使用这个 conver ,否则继续遍历。这个模式有点像 OkHttp
的 Interceptor
一样, 内部通过一层层的拦截器逐步完成, 使用的是责任链模式:它包含了一些命令对象和一系列的处理对象,每一个处理对象决定它能处理哪些命令对象,不同的是,如果前面的 Converter 转换器不能处理那么就交给后面的转换器去处理,直到找到一个能处理的转换器来处理返回数据 ResponseBody
。
看一下 ScalarsConverterFactory
内部是如何处理的:
|
|
代码很简单,就是根据 Type 类型来返回不同类型的 ResponseBodyConverter ,如果没有自己想要处理的类型就直接返回 null,看一下 StringResponseBodyConverter 代码:
|
|
代码很简单直接将 ResponseBody 转换为 String 。
自定义想要的 Converter
既然这个是我们特殊处理的返回结果,那么我们先定义一个特殊的 JavaBean 作为特殊的 Type:
|
|
实现 Factory 逻辑
|
|
自定义 Converter
|
|
上面代码也很简单,没什么好说的,下面是使用我们自定义的 Convert :
使用自定义 Convert
第一步:添加自定义 Converter
|
|
第二步:编写请求接口
|
|
第三步:处理接口返回的 BaseBean<String>
为 Observable<BaseBean<T>>
类型
|
|
第四步:调用处理业务逻辑
|
|
这样我们就不需要一个需要 List 列表的界面定义两个接口,写两套业务逻辑,我们共用一套即可。
总结: Retrofit 和 OKHttp 的设计模式真牛逼!