【android】Retrofit2.0笔记——addConverterFactory同时支持xml和json格式响应数据
Retrofit2的一个特色功能,就是通过addConverterFactory()方法设置一个数据转换器,可以将http请求的响应数据转换成JavaBean。如后台常见的两种返回数据格式:json和xml,分别可以用GsonConverterFactory和SimpleXmlConverterFactory进行转换。对应的gradle依赖分别是:
implementation 'com.squareup.retrofit2:converter-gson:2.x.x'
implementation 'com.squareup.retrofit2:converter-simplexml:2.x.x'
注:
SimpleXmlConverterFactory
目前已被声明为Deprecated,推荐的替代方案为JAXB converter(JaxbConverterFactory
),对应的gradle依赖是:
implementation 'com.squareup.retrofit2:converter-jaxb:2.x.x'
但经过实测,该转换器设置在Retrofit中后不能正常工作。
默认情况下,由于Gson(对于JSON)和SimpleXML(对于XML)转换器的行为,一个Retrofit实例不能同时支持这两个转换器。如果这样写:
Retrofit mRetrofit = new Retrofit.Builder() .baseUrl(URL) .addConverterFactory(SimpleXmlConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build();
那么,转换xml格式的返回数据正常,转换json格式的返回数据则会崩溃。
如果这样写:
Retrofit mRetrofit = new Retrofit.Builder() .baseUrl(URL) .addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(SimpleXmlConverterFactory.create() .build();
那么,转换json格式的返回数据正常,转换xml格式的返回数据则会崩溃。
总之就是,只有先添加的那个可以正常使用。
那有没有可以同时正常转换json和xml格式的方案呢?肯定是有的!
解决思路
给Retrofit要调用的接口方法添加一个注解,说明该请求的响应数据格式。然后自定义一个ConverterFactory,根据注解的属性值决定是使用json转换器还是xml转换器。
实现代码
自定义注解,比如叫ResponseFormat:
/** * 接口返回的数据格式,当前限定取值:{@link #JSON}或{@link #XML} */ @Target(METHOD) @Retention(RUNTIME) public @interface ResponseFormat { String JSON = "json"; String XML = "xml"; String value() default ""; }
自定义ConverterFactory,比如叫JsonOrXmlConverterFactory
:
public class JsonOrXmlConverterFactory extends Converter.Factory { private final Converter.Factory xmlFactory = SimpleXmlConverterFactory.create(); private final Converter.Factory jsonFactory = GsonConverterFactory.create(); public static JsonOrXmlConverterFactory create() { return new JsonOrXmlConverterFactory(); } @Nullable @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { for (Annotation annotation : annotations) { if (!(annotation instanceof ResponseFormat)) { continue; } String value = ((ResponseFormat) annotation).value(); if (ResponseFormat.JSON.equals(value)) { return jsonFactory.responseBodyConverter(type, annotations, retrofit); } else if (ResponseFormat.XML.equals(value)) { return xmlFactory.responseBodyConverter(type, annotations, retrofit); } } return null; } }
测试代码
interface TestApi { @GET("testapi/getjson.php/") @ResponseFormat("json") Observable<OrderResult> getJson(); @GET("testapi/getxml.php/") @ResponseFormat("xml") Observable<OrderResult> getXml(); } //…… Retrofit mRetrofit = new Retrofit.Builder() .baseUrl(URL) .addConverterFactory(JsonOrXmlConverterFactory.create() .build(); //…… public void getCode(Consumer<OrderResult> consumer) { TestApi testApi = mRetrofit.create(TestApi.class); testApi.getJson() .subscribe(consumer); } public void getXml(Consumer<OrderResult> consumer) { TestApi testApi = mRetrofit.create(TestApi.class); testApi.getXml() .subscribe(consumer); }
总结
这个问题虽然有解决方案,但需求场景应该较少。一般后台服务,基于同一个baseUrl的api接口,一般都是统一响应数据格式。只有app中需要从不同的后台服务url请求数据,这样才可能出现多种格式的返回数据,Retrofit本身是支持多baseUrl的。
【参考连接】
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)