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