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的理解又有一些更深的感悟了,实时求实的说多读读开源代码对技能和内功的修炼是非常有帮助的。

原文地址:https://www.cnblogs.com/tony-yang-flutter/p/12364343.html

时间: 2024-10-11 16:15:35

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

Oracle create tablespace 、create user and so on

1.创建临时表空间 CREATE TEMPORARY TABLESPACE test_tempTEMPFILE 'C:\oracle\product\10.1.0\oradata\orcl\test_temp01.dbf'SIZE 32MAUTOEXTEND ONNEXT 32M MAXSIZE 2048MEXTENT MANAGEMENT LOCAL 2.创建用户表空间 CREATE TABLESPACE test_dataLOGGINGDATAFILE 'C:\ORACLE\PRODUCT\

[原创] Delphi Create(Application) 和 Create(nil) 的区别

Delphi Create(Application) 和 Create(nil) 的区别: 例如: Form1:=TForm1.Create(Application); Form1:=TForm1.Create(nil): Create(Application)  :程序创建时会将对象添加到属主对象的组件(TComponent)列表中,当属主对象销毁时首先查看并销毁属主对象的从属对象,即当Application对象释放时会自动释放从属对象. 这里又要衍生一个概念及应用程序对象即Applicati

MYSQL create database 和 create table 做了一些什么!

create database Studio; 这样就可以创建一个数据库了.他包涵一些什么呢? 可以看到它创建了一个文件夹,下面我们进去看一下它里面有一些什么东西. 还是先建一张表再进去吧,运行一下这个  create table Nums(X int not null); 内容分析: db.opt 文件. 复制到另一个地方,用计事本打开. 发现它保存的是字符集与排序规则信息. .frm 文件. 它保存整个表框架的定义,但是它保存的是密文. .idb文件. 它用来保存表中的数据.

Xcode引入外界文件时选Create groups 或 Create folder references的区别

一.使用Create groups 我们在项目中可以手动添加一个groups(右键点击选择New Group),但是手动添加的groups实际上并不会存在于项目的目录中,被添加进groups中的文件仍在位于它原来所在的位置,但从外部引入进来的groups并不会如此.groups一旦被创建或添加,都是以黄色文件夹的形式存在的,当你想要使用文件夹中的某个类的头文件时,你可以直接添加它的引用.因为groups下的cpp文件是会被编译的. 二.使用Create folder references方法只是

SQL高级应用(CREATE DATABASE、CREATE TABLE)

SQL CREATE DATABASE CREATE DATABASE 用于创建数据库,语法如下 CREATE DATABASE database_name 例子:创建一个名为 db_test的数据库 CREATE DATABASE db_test 可以通过 CREATE TABLE 来添加数据库表. SQL CREATE TABLE CREATE TABLE 语句用于创建数据库中的表,语法如下 CREATE TABLE table_name ( 列名称1 数据类型, 列名称2 数据类型, 列名

Mysql 的 create as 和create like 区别

大家可能使用Navicat Premium时发现很方便,比如复制表或数据结构等,其实这种复制表数据或结构方法就是create table as 和create table like 这种方式实现细心的朋友会问,他们有啥区别呢?...废话不多说,直入正题:比如这里有张表数据t1: DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID,自增',

create table 和 create schema的区别

什么是Database,什么是Schema,什么是Table,什么是列,什么是行,什么是User? 我们可以把Database看作是一个大仓库,仓库分了很多很多的房间,Schema就是其中的房间,一个Schema代表一个房间. Table可以看作是每个Schema中的床,Table(床)就被放入每个房间中,不能放置在房间之外,那岂不是晚上睡觉无家可归了. 然后床上可以放置很多物品,就好比Table上可以放置很多列和行一样,数据库中存储数据的基本单元是Table,现实中每个仓库放置物品的基本单位就

浅谈Retrofit2+Rxjava2

近几年,Retrofit犹如燎原之火搬席卷了整个Android界.要是不懂Retrofit,简直不好意思出门...由于近几个项目都没用到Retrofit,无奈只能业余时间自己撸一下,写的不好的地方,还请不吝赐教.要集成retrofit,在app的bild.gradle中添加库以来就可以: compile 'com.squareup.retrofit2:retrofit:2.3.0' 如果需要集成json解析,还需要添加库: compile 'com.squareup.retrofit2:conv

Android 使用Retrofit2.0+OkHttp3.0实现缓存处理+Cookie持久化第三方库

1.Retrofit+OkHttp的缓存机制 1.1.第一点 在响应请求之后在 data/data/<包名>/cache 下建立一个response 文件夹,保存缓存数据. 1.2.第二点 这样我们就可以在请求的时候,如果判断到没有网络,自动读取缓存的数据. 1.3.第三点 同样这也可以实现,在我们没有网络的情况下,重新打开App可以浏览的之前显示过的内容. 1.4.第四点 也就是:判断网络,有网络,则从网络获取,并保存到缓存中,无网络,则从缓存中获取. 1.5.github地址+参考文章 g