Retrofit2.0的Converter使用
来源:互联网 发布:网络创意广告分析报告 编辑:程序博客网 时间:2024/04/28 06:18
在Retrofit中, 不管是发送数据或是接收数据, 最基本都是通过OKHttp的RequestBody和ResponseBody来实现,但是通常为了方便,我们在定制协议的时候,不会直接使用原始的RequestBody或是ResponseBody,因此,在Retrofit中,我们就需要对它进行转换。
在Retrofit的类的定义中,有个converterFactories的List,我们可以在build时添加多个,但要注意的是,添加的顺序是有影响的。
private final List<Converter.Factory> converterFactories;
按照retrofit的逻辑,是从前往后进行匹配,如果匹配上,就忽略后面的,直接使用。
int start = converterFactories.indexOf(skipPast) + 1; for (int i = start, count = converterFactories.size(); i < count; i++) { Converter.Factory factory = converterFactories.get(i); Converter<?, RequestBody> converter = factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this); if (converter != null) { //noinspection unchecked return (Converter<T, RequestBody>) converter; } }
从上面的源码中可以看到,当factory.requestBodyConverter返回空时,表示没有匹配上,可使用下一个factory.
因此,当我们自定义converter的时候,需要进行条件判断,符合我们一定规则的才能使用。
Type
我们以创建protobuff为例。
public final class ProtoConverterFactory extends Converter.Factory { public static ProtoConverterFactory create() { return new ProtoConverterFactory(); } @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { //进行条件判断,如果传进来的Type不是class,则匹配失败 if (!(type instanceof Class<?>)) { return null; } //进行条件判断,如果传进来的Type不是MessageLite的实现类,则也匹配失败 Class<?> c = (Class<?>) type; if (!MessageLite.class.isAssignableFrom(c)) { return null; } Parser<MessageLite> parser; try { Field field = c.getDeclaredField("PARSER"); //noinspection unchecked parser = (Parser<MessageLite>) field.get(null); } catch (NoSuchFieldException | IllegalAccessException e) { throw new IllegalArgumentException( "Found a protobuf message but " + c.getName() + " had no PARSER field."); } //返回一个实现了Converter的类, return new ProtoResponseBodyConverter<>(parser); } @Override public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { //进行条件判断,如果传进来的Type不是class,则匹配失败 if (!(type instanceof Class<?>)) { return null; } //进行条件判断,如果传进来的Type不是MessageLite的实现类,则也匹配失败 if (!MessageLite.class.isAssignableFrom((Class<?>) type)) { return null; } return new ProtoRequestBodyConverter<>(); }}
注意在Convert的两个泛型中,前一个类型是传进来的对象类型,后一个类型是转换后的对象类型。
final class ProtoRequestBodyConverter<T extends MessageLite> implements Converter<T, RequestBody> { private static final MediaType MEDIA_TYPE = MediaType.parse("application/x-protobuf"); @Override public RequestBody convert(T value) throws IOException { byte[] bytes = value.toByteArray(); return RequestBody.create(MEDIA_TYPE, bytes); }}
final class ProtoResponseBodyConverter<T extends MessageLite> implements Converter<ResponseBody, T> { private final Parser<T> parser; ProtoResponseBodyConverter(Parser<T> parser) { this.parser = parser; } @Override public T convert(ResponseBody value) throws IOException { try { return parser.parseFrom(value.byteStream()); } catch (InvalidProtocolBufferException e) { throw new RuntimeException(e); // Despite extending IOException, this is data mismatch. } finally { value.close(); } }}
Annotation
在有一些情况,仅仅通过type来进行判断,信息是不够的,还需要额外的参数。这时我们就可以利用后面两个参数来进行。
我们先看requestBodyConverter的函数签名。
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit)
显然,parameterAnnoatations是指在定义接口的参数上的注解。如下面的MyType:
@GET("applist/mini-appcenter/") Call<MiniAppCenterPojo> getMiniApp(@Query("offsets") @TypeString String offsets);
定义在方法上的注释就是methodAnnotations
@TypeString @GET("applist/mini-appcenter/") Call<MiniAppCenterPojo> getMiniApp(@Query("offsets") String offsets);
我们就可以通过对这些注解的判断来进行自定义Converter的匹配。
@Documented@Target(PARAMETER)@Retention(RUNTIME)public @interface TypeString{}
public class StringConverterFactory extends Converter.Factory { @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { if (!(type instanceof Class<?>)) { return null; } for( Annotation annotation :annotations) { if( annotation instanceof TypeString) { return new StringResponseConverter(); } } return null; } @Override public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { if (!(type instanceof Class<?>)) { return null; } for( Annotation annotation :parameterAnnotations) { if( annotation instanceof TypeString) { return new StringRequestConverter(); } } return null; } public static class StringResponseConverter implements Converter<ResponseBody, String> { @Override public String convert(ResponseBody value) throws IOException { return value.string(); } } public static class StringRequestConverter implements Converter<String, RequestBody> { @Override public RequestBody convert(String value) throws IOException { return RequestBody.create(MediaType.parse("application/octet-stream"), value); } }}
0 0
- Retrofit2.0的Converter使用
- Retrofit2 使用FastJson作为Converter
- Retrofit2.0的使用
- Retrofit2.0 的使用
- Retrofit2.0的使用
- Retrofit2.0的使用
- Retrofit2自定义Converter.Factory
- Retrofit2.0 的初步使用
- retrofit2.0的简单使用
- Retrofit2.0的简单使用
- Retrofit2.0的使用总结
- Retrofit2.0的使用详解
- Retrofit2.0的简单使用
- Retrofit2.0的基本使用
- Retrofit2.0的简单使用
- Apt实践:Retrofit2.0 + 非Restful API + Apt Converter
- RxJava和Retrofit2.0的结合使用
- Retrofit2.0+RxJava+MVP+Bmob的使用
- 星期几(蓝桥杯)
- 牛人的ACM经验 (转)
- 常用字符串长度计算函数
- ionic splash screen 之后出现的白屏解决办法
- 算法代码实现之快速排序,Java实现
- Retrofit2.0的Converter使用
- 20160229 ADO.NET连接SQL Server数据库(SqlHelper类)
- WTF交换
- 自适应中值滤波
- 如何演示你的App?Android录制Gif动态图教程
- Android中的RxJava详解
- ACM做题过程中的一些小技巧
- 秋实大哥与快餐店(二进制+字典树)
- <<第一行代码>>--全局获取Context技巧