Retrofit2的GsonConverterFactory.create()和RxJava2CallAdapterFactory.create()的实现过程以及执行过程

Posted 飘杨......

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Retrofit2的GsonConverterFactory.create()和RxJava2CallAdapterFactory.create()的实现过程以及执行过程相关的知识,希望对你有一定的参考价值。

一概述

  上一节分析了retrofit2从创建到执行的完整流程,本节分析一下两个非常重要的功能。数据转换器的实现以及网络请求适配器的实现。

二、GsonConvertFactory.create()数据转换器的实现过程以及执行过程

  我们先看下GsonConvertFactory.crete()的源代码,此类在retrofit-converters插件中

public final class GsonConverterFactory extends Converter.Factory {
  //创建GsonConverterFactory对象
  public static GsonConverterFactory create() {
    return create(new Gson());
  }

  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static GsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new GsonConverterFactory(gson);
  }

  private final Gson gson;

  private GsonConverterFactory(Gson gson) {
    this.gson = gson;
  }
  //将请求结果的body进行转换
  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    //这里的TypeAdapter是Gson中用来做序列化和反序列化用的
    //其中TypeToken.get(type)是用来获取一个类类型
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
  //最后返回一个jsonResponse对象做解析工作 return new GsonResponseBodyConverter<>(gson, adapter); } //转换请求结果的body @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); } }

  我们看一下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;
  }
  //这里的convert方法是Converter接口中定义的convert
  @Override public T convert(ResponseBody value) throws IOException {
    //创建一个JsonReader对象,jsonReader是gson中的类供TypeAdapter序列化以及反序列化时使用的。
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      //通过TypeAdapter把读取到的对象转换为泛型
      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();
    }
  }
}

看下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;
  }
  //实现Converter接口的convert方法
  @Override public RequestBody convert(T value) throws IOException {
    Buffer buffer = new Buffer();
    Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
    //创建一个jsonwriter
    JsonWriter jsonWriter = gson.newJsonWriter(writer);
    //把http请求信息进行序列化
    adapter.write(jsonWriter, value);
    jsonWriter.close();
    //然后把序列化后的结果放到RequestBody中
    return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
  }

  

看下Converter.Factroy的源代码,Converter是一个接口,Factory是其内部抽象类。其中定义了各种类型转换的接口。

//数据转换接口
public interface Converter<F, T> {
  //数据转换接口 @Nullable T convert(F value) throws IOException; /** Creates {@link Converter} instances based on a type and target usage. */ abstract class Factory { //转换网络请求的返回结果 public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { return null; } //转换请求结果 public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { return null; }

 具体的转化代码也就这么多,都是操作Gson的一系列方法实现的。下面看看GsonConvertFactory是如何在框架中调用的。

 首先要明确一点,既然是响结果转换器,其必定是响应结果前实现回调的,即在Callback回调函数前需要把响应结果给转换后再给Callback。

 上一节我们说过我们生成的Call其实就是DefaultCallAdapterFactory中的ExecutorCallbackCall。然而ExecutorCallbackCall中却没有看得到Converter的身影。ExecutorCallbackCall的源码如下:

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      Objects.requireNonNull(callback, "callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(() -> {
            if (delegate.isCanceled()) {
              // Emulate OkHttp‘s behavior of throwing/delivering an IOException on cancellation.
              callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
            } else {
              callback.onResponse(ExecutorCallbackCall.this, response);
            }
          });
        }

        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
        }
      });
    }

  那么接着往上一级目录找找,我们记得在HttpMethodService类的内部有一个invoke方法,其会调用他的实现类CallAdapted类的adapt方法,方法内部会调用DefaultCallAdapterFactory的adapt方法并返回一个ExecutorCallbackCall。并传入一个Call和方法的参数。这个Call的实现类就是HttpCall。你没看错响应结果转换就发生在这个类中。

  @Override final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

  protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

  static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;

    CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }

    @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }
  }

 既然已经确定了响应数据转换在HttpCall中发生。那我们看下他具体做了什么事情。

final class OkHttpCall<T> implements Call<T> {
  private final RequestFactory requestFactory;
  private final Object[] args;
  private final okhttp3.Call.Factory callFactory;
  private final Converter<ResponseBody, T> responseConverter;

  private volatile boolean canceled;

  @GuardedBy("this")
  private @Nullable okhttp3.Call rawCall;
  @GuardedBy("this") // Either a RuntimeException, non-fatal Error, or IOException.
  private @Nullable Throwable creationFailure;
  @GuardedBy("this")
  private boolean executed;

  OkHttpCall(RequestFactory requestFactory, Object[] args,
      okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) {
    this.requestFactory = requestFactory;
    this.args = args;
    this.callFactory = callFactory;
    this.responseConverter = responseConverter;
  }

  果然如上面我们分析的那样,HttpCall接收了一个Converter<ResponseBody,T> responseConverter变量。而这个变量就是我们创建retrofit设置的GsonConvertFactory.create()。

  在HttpCall的内部有一个enqueue(callback)方法,其内部会调用parseResponse方法。parseResponse内部会调用convert方法对数据进行转换。这个convert方法就是上面我们提到的GsonResponseBodyConvert。

  HttpCall的enqueue方法

  

@Override public void enqueue(final Callback<T> callback) {
    ...省略了前面的一些代码
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          throwIfFatal(e);
          callFailure(e);
          return;
        }

        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }

    ....省略了一些代码
    });
  }

  接下来看下parseResponse方法

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    // Remove the body‘s source (the only stateful object) so we can pass the response along.
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();
...省略了一些diamante ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody); try { //在此处做转换操作,这里的responseConverter就是GsonResponseBodyConverter T body = responseConverter.convert(catchingBody); //把body设置进去 return Response.success(body, rawResponse); } catch (RuntimeException e) { catchingBody.throwIfCaught(); throw e; } }

  到这里转换操作就完成了,converter方法的具体实现可以参考上面的GsonResponseBodyConverter源码。

总结:通过Retrofit设置响应数据转换器GsonConvertFactory.create(),在HttpCall中的enqueue方法中的parseResponse做具体的转换,转换调用的是responseConverter.convert(catchingBody)。其中responseConverter的具体转换操作是在GsonResponseBodyConverter中完成的。好了GsonConvertFactory.create()的源码以及执行流程就这样分析完了。

  ps:补充一下自定义响应数据解析器

  根据上面的分析我们知道创建响应数据解析器的时候解析器需要继承Converter.Factory,并实现Converter.Factory的responseBodyConverter接口。那么我们在自定义响应数据解析器的时候也可以这么干。三部搞定

  1.创建一个XmlConverterFactory并继承Converter.Factory的并实现其responseBodyConverter方法

  2.创建一个具体的解析类,并当做responseBodyConverter的返回值

  3.在retrofit的Builder中注解解析器XmlConverterFactory.create()

  下面是以上三步的示例代码:

/**
 * xml响应数据解析器
 * create by yangwei
 * on 2020-02-25 20:12
 */
public class XmlConverterFactory extends Converter.Factory {
    public static XmlConverterFactory create() {
        return new XmlConverterFactory(new Xml());
    }

    public static XmlConverterFactory create(Xml xml) {
        return new XmlConverterFactory(xml);
    }

    @javax.annotation.Nullable
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {

        return new XmlResponseBodyFactory();
    }
}

  

/**
 * create by yangwei
 * on 2020-02-25 20:16
 */
public class XmlResponseBodyFactory implements Converter<T, RequestBody> {
    private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");
    @javax.annotation.Nullable
    @Override
    public RequestBody convert(T value) throws IOException {
        //此处做具体转换操作
        return RequestBody.create(MEDIA_TYPE,value.bytes);
    }
}

  在Retrofit的Builder中设置其网络请求数据转换器

Retrofit retrofit = new Retrofit.Builder().
                baseUrl("http://www.xxxx.com/").//请求地址
                addConverterFactory(XmlConverterFactory.create()).//自定义xml网络请求结果转换器
                addCallAdapterFactory(RxJava2CallAdapterFactory.create()).//网络请求适配器
                build();

  自定义的示例代码就写完了,大家在实际的开发过程中可以根据需要自行添加自定义网络请求结果转换器,或者对转换器进行修正。

三、RxJava2CallAdapterFactory.create()网络请求适配器的实现过程以及执行过程

  上一节分下了默认的请求网络适配器DefaultCallAdapterFactory。让我们先来回顾下它具体是如何工作的。

  首先在retrofit的builder中进行设置,不设置也行默认就是使用的DefaultCallAdapterFactory请求网络适配器。

  在上一节中我们通过retrofit的create方法动态生成了一个接口实例,并调用接口实例的方法返回了一个Call,生成过程是调用loadServiceMethod.invoke(map)方法,ServiceMethod是个抽象类, 其实现类是HttpServiceMethod,在HttpServiceMethod中重新会真正的调用invoke方法,并实例化一个OkHttpCall,通过其HttpServiceMethod的invoke方法,在其方法内部会调用DefaultCallAdapterFactory.adapt方法,DefaultCallAdapterFactory的adapt方法会生成一个ExecutorCallbackCall并返回。

  下面说说RxJava2CallAdapterFactory网络请求适配器是如何实现的,其实原理和前面说的也是差不多的,至少前半部分是相同的。

  我们直接从HttpServiceMethod内部类CallAdapted类的adapt方法开始说: 

  @Override ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }

  从这里往前的部分都是和DefaultCallAdapterFactory一样的。这里的callAdapter其实指的就是前面设置的RxJava2CallAdapterFactory。那么我们直接把逻辑切换到RxJava2CallAdapterFactory中看就行了。

public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
 
  public static RxJava2CallAdapterFactory create() {
    return new RxJava2CallAdapterFactory(null, false);
  }

  public static RxJava2CallAdapterFactory createAsync() {
    return new RxJava2CallAdapterFactory(null, true);
  }

  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static RxJava2CallAdapterFactory createWithScheduler(Scheduler scheduler) {
    if (scheduler == null) throw new NullPointerException("scheduler == null");
    return new RxJava2CallAdapterFactory(scheduler, false);
  }

  从RxJava2CallAdapterFactory的源码中可以看出,其继承了CallAdapter.Factory。看着是不是眼熟?是不是和Converter.Factory的形式差不多。那么我们推测一下CallAdapter其实是一个接口,Factory是接口内部的抽象类,我们看下源码是否是这么回事

public interface CallAdapter<R, T> {
  Type responseType();

  T adapt(Call<R> call);
  abstract class Factory {
    public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
        Retrofit retrofit);
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}

  恩,确实和我们推测的一样,集成Factory就会实现,get、getparameterUpperBound和getRawType方法。而实现CallAdapter则必须实现Adapt方法

  我们接着看CallAdapter.adapt方法,在adapt中会把传递进来的OkHttpCall包装成CallEnqueueObservable或者CallExecuteObservable。之后会把这两个Observable再经过一次包装,包装成ResultObservable或者BodyObservable然后返回

  RxJava2CallAdapter.adapt

@Override public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }

    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return RxJavaPlugins.onAssembly(observable);
  }

  到目前为止retrofit的接口实例方法已经返回了一个Observable,且此Observable已经包装了一个OkHttpCall。

在调用Observable.subscribe执行订阅的时候会先通过CallEnqueueObservable调用subscribeActual,接着会调用ResultObservable的subscribeActual方法进行绑定.

接下来看下发起网络请求的的地方在哪里,即call.enqueue

final class CallEnqueueObservable<T> extends Observable<Response<T>> {
  private final Call<T> originalCall;

  CallEnqueueObservable(Call<T> originalCall) {
    this.originalCall = originalCall;
  }

  @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    Call<T> call = originalCall.clone();
    CallCallback<T> callback = new CallCallback<>(call, observer);
    observer.onSubscribe(callback);
  //此处是真正发起网络请求的地方 if (!callback.isDisposed()) { call.enqueue(callback); } } private static final class CallCallback<T> implements Disposable, Callback<T> { private final Call<?> call; private final Observer<? super Response<T>> observer; private volatile boolean disposed; boolean terminated = false; CallCallback(Call<?> call, Observer<? super Response<T>> observer) { this.call = call; this.observer = observer; } @Override public void onResponse(Call<T> call, Response<T> response) { if (disposed) return; try { observer.onNext(response);

  真正发起网络请求的地方在CallEnqueueObservable中的subscribeActua通过OkHttpCall的enqueue发起。当请求完成并且响应结果后会回调Callback接口的onResponse方法

@Override public void onResponse(Call<T> call, Response<T> response) {
      if (disposed) return;

      try {
        observer.onNext(response);

        if (!disposed) {
          terminated = true;
          observer.onComplete();
        }
      } catch (Throwable t) {

  而在onResponse方法的内部会调用observer的onNext方法返回请求结果,而onNext方法又会调用LambdaObserver的onNext方法。而LambdaObserver的onNext方法就会调用观察者的回调函数。

ps:自定义网络请求适配器的方法和数据转换器的步骤类似,不再赘述。如果不会,参考RxJava2CallAdapterFactory的实现就行了。

四、总结

  经过分析GsonConverterFactory和RxJava2CallAdapterFactory相信大家对retrofit的理解又有一些更深的感悟了,实时求实的说多读读开源代码对技能和内功的修炼是非常有帮助的。

以上是关于Retrofit2的GsonConverterFactory.create()和RxJava2CallAdapterFactory.create()的实现过程以及执行过程的主要内容,如果未能解决你的问题,请参考以下文章

Retrofit2 项目配置

Retrofit2 简明教程

Retrofit2源码分析

Retrofit2

Retrofit2

Retrofit2