秒懂Retrofit2之GsonConverterFactory

版权申明】非商业目的可自由转载
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/81387328
出自:shusheng007

系列文章
最简单易懂的Retrofit2源码详解
用Retrofit+RxJava2封装优雅的网络请求框架

概述

前两天分析了Retrofit的源码,个人认为其精髓就在于CallAdapterConverter的设计上,本文我们就先研究下Converter的知识,下一篇再研究CallAdapter

Converter的作用

假设我们不为Retrofit设置任何Converter,那么Retrofit能正常工作吗?有什么限制?先看下面代码:

code1

    @POST
    @Multipart
    Call<ResponseBody>method1(@Part("p") RequestBody rBody);

    @POST
    Call<Void>method2(@Body RequestBody rBody);

code2

    @POST
    @Multipart
    Call<String>method1(@Part("p") Map<String,String> rBody);

    @POST
    Call<List<User>>method2(@Body User rBody);

code1 是没有添加自定义converter时可以做的,而code2是添加了GsonConverter后可以做的。可以发现仅仅使用默认的converter的话会在使用上存在巨大限制。

  • 对于方法的请求参数来说

    使用@Part,@PartMap,@Body标记的参数类型就只能是RequestBody

  • 对于方法的返回结果来说

    方法放回结果的泛型参数只支持ResponseBodyVoid

那样对我们的使用来说就麻烦了许多,需要不断的将数据在我们自己的类型与ResponseBody之间互相转换。而GsonConverterFactory就是为了将这个数据类型转换的工作自动化而生的。

GsonConverterFactory源码解析

得益于Gson的强大,使的 GsonConverterFactory非常简单,源码也仅仅只有3个类。
这里写图片描述

GsonConverterFactory

我就是通过这个工厂来调用请求转换器requestBodyConverter结果转换器responseBodyConverter

public final class GsonConverterFactory extends Converter.Factory {

  //最常使用的静态工厂方法,使用默认的Gson实例 
  public static GsonConverterFactory create() {
    return create(new Gson());
  }

  //使用这个工厂方法可以从外部传入Gson对象,我们可以对这个Gson对象做很多配置
  public static GsonConverterFactory create(Gson gson) {
    ...
    return new GsonConverterFactory(gson);
  }

  private final Gson gson;
  private GsonConverterFactory(Gson gson) {
    this.gson = gson;
  }

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonRequestBodyConverter<>(gson, adapter);
  }
}

源码简洁的令人发指,首先由两个静态工厂方法可以获得对象实例,其中一个可以出入一个Gson对象,这就产生了很多想象空间。因为我们可以在外部配置这个Gson对象的各种属性,关于如何配置,希望你调研一下,肯定又会惊叹于Gson设计的精妙。剩下两个函数我都不好意思讲了,不然会有侮辱读者智商的嫌疑。

GsonRequestBodyConverter

请求转化器

final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
  private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");
  private static final Charset UTF_8 = Charset.forName("UTF-8");

  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override public RequestBody convert(T value) throws IOException {
    Buffer buffer = new Buffer();
    Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
    JsonWriter jsonWriter = gson.newJsonWriter(writer);
    adapter.write(jsonWriter, value);
    jsonWriter.close();
    return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
  }
}

结构很清晰,就是将一个T类型的数据value,例如为User,通过convert()转化为RequestBody类型的数据。如果你觉得看不懂,肯定不是看不懂逻辑而是看不懂转换的代码,别装了,承认看不懂不难!那就去研究Gson吧,少年!

GsonResponseBodyConverter

结果转换器

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      T result = adapter.read(jsonReader);
      if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
        throw new JsonIOException("JSON document was not fully consumed.");
      }
      return result;
    } finally {
      value.close();
    }
  }
}

结构仍然很清晰,就是通过convert()RequestBody类型的value数据转换为我们期望的T类型的数据,例如TUser。如果你又觉得看不懂,肯定不是看不懂逻辑而是看不懂转换的代码,别装了,承认看不懂不难!那就去研究Gson吧,少女!

总结

目前除了GsonConverter以外,源码中还包含了很多其他的的转换器,例如jacksonguavejava8simplexml等等,当遇到相应的场景时可以使用,如果现存的Converter不能满足我们的需求,我们就需要自己开发一个转换器了。

猜你喜欢

转载自blog.csdn.net/ShuSheng0007/article/details/81387328