秒懂Retrofit2之GsonConverter

ShuSheng007發表於2018-08-03

版權申明】非商業目的可自由轉載
博文地址: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不能滿足我們的需求,我們就需要自己開發一個轉換器了。

相關文章