美文网首页Rx系列
Retrofit解析7之相关类解析

Retrofit解析7之相关类解析

作者: 隔壁老李头 | 来源:发表于2017-06-27 22:18 被阅读354次

    整体Retrofit内容如下:

    上篇文章讲解了Call接口、CallAdapter接口、Callback接口、Converter接口、Platform类、ExecutorCallAdapterFactory类、HttpException类。而本片文章讲解剩下的几个类。内容如下:

    • 1、GsonConverterFactory类
    • 2、BuiltInConverters类
    • 3、RequestBuilder类
    • 4、Response类
    • 5、OkHttpCall类

    一、GsonConverterFactory类

    (一)GsonConverterFactory 简介

    1、GsonConverterFactory在哪里?

    有人会问GsonConverterFactory这个类在那?我怎么在Retrofit源码里面找不到,其实这个GsonConverterFactory类不在Retrofit里面,需要你在应用的时候添加的。如果很多Retrofit的程序员都是用Gson来进行反序列化的,所以他们会在他们的gradle里面添加,如下:

    dependencies {
        //省略部分....
        compile 'com.squareup.retrofit2:converter-gson:2.1.0'
        //省略部分....
    }
    

    然后在代码里面添加

        //设置返回数据类型
       Retrofit.Builder.addConverterFactory(GsonConverterFactory.create()) 
    

    这样 Retrofit就可以使用GsonConverterFactory

    2、GsonConverterFactory 简介

    为了更好的体验作者的意图,我这边直接把这个GsonConverterFactory类的类注释,大家一起研究下

    /**
     * A {@linkplain Converter.Factory converter} which uses Gson for JSON.
     * <p>
     * Because Gson is so flexible in the types it supports, this converter assumes that it can handle
     * all types. If you are mixing JSON serialization with something else (such as protocol buffers),
     * you must {@linkplain Retrofit.Builder#addConverterFactory(Converter.Factory) add this instance}
     * last to allow the other converters a chance to see their types.
     */
    

    我来先简单翻译一下:

    使用Gson在解析JSON的一个转化器
    由于Gson在兼容类型方面比较灵活,所以假设它可以处理所有类型。如果你想在其他方面(比如协议缓冲区protocol buffers)也使用该JSON转化器,为了让他其他转化器知道它们对应代理类型,则必须调用Retrofit.Builder的addConverterFactory(Converter.Factory)方法,来添加这个实例。

    所以我们总结一下,就是一个JSON解析的转化器

    (二)"com.squareup.retrofit2:converter-gson:2.1.0"的包结构

    如下图:

    包结构.png

    我们发现好简单,就3个类耶,那我们就一个一个来看
    先看下GsonConverterFactory

    (三) 类源码解析

    1、GsonConverterFactory 源码解析

    这个类的类注释已经讲解过了,我就不再讲解了。直接上源码

    /**
     * A {@linkplain Converter.Factory converter} which uses Gson for JSON.
     * <p>
     * Because Gson is so flexible in the types it supports, this converter assumes that it can handle
     * all types. If you are mixing JSON serialization with something else (such as protocol buffers),
     * you must {@linkplain Retrofit.Builder#addConverterFactory(Converter.Factory) add this instance}
     * last to allow the other converters a chance to see their types.
     */
    public final class GsonConverterFactory extends Converter.Factory {
      /**
       * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
       * decoding from JSON (when no charset is specified by a header) will use UTF-8.
       */
      public static GsonConverterFactory create() {
        return create(new Gson());
      }
    
      /**
       * Create an instance using {@code gson} for conversion. Encoding to JSON and
       * decoding from JSON (when no charset is specified by a header) will use UTF-8.
       */
      public static GsonConverterFactory create(Gson gson) {
        return new GsonConverterFactory(gson);
      }
    
      private final Gson gson;
    
      private GsonConverterFactory(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        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);
      }
    }
    

    代码很少,我们来看下他的结构


    GsonConverterFactory结构.png

    通过代码和结构图,我们知道以下几点

    • 构造函数是private,所以不能直接new,但是他提供了两个public的静态方法来创面一个GsonConverterFactory对象。
    • GsonConverterFactory是final的不能被继承。
    • 内部有一个final的Gson类型的变量gson,在构造GsonConverterFactory被初始化
    • 如果调用GsonConverterFactory类的静态方法创建GsonConverterFactory 有两个,一个是需要传入Gson对象,一个不需要传入Gson对象,而这个不传入Gson对象的静态方法,其实内部也是自己直接new的一个Gson对象。
    • 内部定义两个public方法responseBodyConverter和requestBodyConverter
    • responseBodyConverter和requestBodyConverter方法里面均通过gson.getAdapter方法获取TypeAdapter(类型适配器)对象,这个TypeAdapter(类型适配器)对象作为构造函数的参数传入GsonResponseBodyConverter和GsonRequestBodyConverter中。

    那我们来看下具体看下这两个方法内部都作了什么?

      @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);
      }
    

    GsonConverterFactory类定义了两个方法返回不同的Converter,一个是针对解析响应体(ResponseBody)的转化器,一个是对应请求体(RequestBody)的转化器,大家注意,他这里有进一步解耦了,因为如果是一般人,包括笔者,肯定直接就在这里直接定义具体的解析的流程,而GsonConverterFactory没有,他是直接定义两个类,针对两个不同的情况。这样,解析响应体(ResponseBody)和解析请求体(RequestBody)就进一步解耦了。所以,我们知道GsonResponseBodyConverter是负责转化响应体(ResponseBody)的,而GsonRequestBodyConverter是负责转化请求体(RequestBody)的

    2、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 {
          return adapter.read(jsonReader);
        } finally {
          value.close();
        }
      }
    }
    

    比较简单,直接说结论了

    • GsonResponseBodyConverter是final的不能被继承
    • 内部有两个变量分别是Gson类型的gson和TypeAdapter<T>的adapter,两者是在构造函数里面初始化的。
    • 实现Converter<ResponseBody, T>,所以实现了T convert(ResponseBody) 方法,内部是通过gson的newJsonReader的方法获取JsonReader对象,然后用TypeAdapter的read来获取对应的类型T
    3、GsonRequestBodyConverter 源码解析

    这个类比较简单,直接上源码了

    final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
      private static final MediaType MEDIA_TYPE = MediaType.parse("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());
      }
    }
    

    比较简单,直接说结论了,内容如下:

    • GsonRequestBodyConverter是final的不能被继承
    • 内部有两个变量分别是Gson类型的gson和TypeAdapter<T>的adapter,两者是在构造函数里面初始化的。
    • 字符支持是 UTF-8的
    • 实现 converter<T, RequestBody>,所以实现了RequestBody convert(T value) 方法,首先获取输出流,然后通过gson.newJsonWriter()方法获取JsonWriter对象,最后通过 adapter.write()写入数据。最后调用RequestBody.create()方法获取一个RequestBody。

    PS:

    关于Gson的相关知识,后面有时间再仔细讲解下,今天就不说了。

    至此,GsonConverterFactory已经讲解完毕,希望他对能能理解。

    二、BuiltInConverters

    BuiltInConverters类Retrofit内部自带的转化器,也就是默认的转化器。受篇幅限制,我就不上源码了,希望大家理解

    通过源码我们知道如下内容

    • BuiltInConverters是final的不允许继承
    • BuiltInConverters里面就两个方法,即重写了responseBodyConverter和requestBodyConverter两个方法,它并重写stringConverter这个方法。
    • 它内部有5个静态内部类。那我们就挨个分析
    1、responseBodyConverter方法分析

    主要是把响应体转化为指定的格式,其实就是反序列化的过程,内容不多,大家看下源码:

      @Override
      public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
          Retrofit retrofit) {
          //如果type类型是ResponseBody
        if (type == ResponseBody.class) {
          //判断是二进制流的形式,还是字符的形式,返回不同的对象,如果是二进制流的形式,返回静态内部类StreamingResponseBodyConverter的单例,如果是字符,则返回静态内部类BufferingResponseBodyConverter的单例。
          return Utils.isAnnotationPresent(annotations, Streaming.class)
              ? StreamingResponseBodyConverter.INSTANCE
              : BufferingResponseBodyConverter.INSTANCE;
        }
         //如果是Void则说明不关心响应体,所以由静态内部类VoidResponseBodyConverter的单例来处理。
        if (type == Void.class) {
          return VoidResponseBodyConverter.INSTANCE;
        }
        //由于是默认的转化器,只处理ResponseBody和Void的类型
        return null;
      }
    

    内容不多,我就不讲解,大家看注释吧

    2、requestBodyConverter方法分析

    这个方法主要是把对象写入到请求体重,内容不多,直接上源码,受篇幅限制,直接上注释,就不解释了。

      @Override
      public Converter<?, RequestBody> requestBodyConverter(Type type,
          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        //如果type的原始接口和RequestBody一致,则调用静态内部类RequestBodyConverter的实例
        if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
          return RequestBodyConverter.INSTANCE;
        }
         //默认只支持RequestBody的类型
        return null;
      }
    
    3、静态内部类分析RequestBodyConverter

    这个类很简单, convert()方法直接返回value

      static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
        static final RequestBodyConverter INSTANCE = new RequestBodyConverter();
    
        @Override public RequestBody convert(RequestBody value) throws IOException {
          return value;
        }
      }
    
    4、静态内部类分析StreamingResponseBodyConverter

    这个类很简单, convert()方法直接返回value

      static final class StreamingResponseBodyConverter
          implements Converter<ResponseBody, ResponseBody> {
        static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();
    
        @Override public ResponseBody convert(ResponseBody value) throws IOException {
          return value;
        }
      }
    
    5、静态内部类分析BufferingResponseBodyConverter

    这个类很简单, convert()方法直接返回value

      static final class BufferingResponseBodyConverter
          implements Converter<ResponseBody, ResponseBody> {
        static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
    
        @Override public ResponseBody convert(ResponseBody value) throws IOException {
          try {
            // Buffer the entire body to avoid future I/O.
             //通过调用Utils的buff()方法来获取一个ResponseBody对象,其实Utils的buff()内部调用ResponseBody.create()来获取一个ResponseBody
            return Utils.buffer(value);
          } finally {
            value.close();
          }
        }
      }
    
    6、静态内部类分析BufferingResponseBodyConverter

    convert()方法起就是调用对象自己的toString()方法。

      static final class ToStringConverter implements Converter<Object, String> {
        static final ToStringConverter INSTANCE = new ToStringConverter();
    
        @Override public String convert(Object value) {
          return value.toString();
        }
      }
    

    总结

    • BuiltInConverters根据不同的类型,来把具体转化交给具体的静态内部类去处理,实现了解耦。
    • 大部分的转化,其实都没有转化,都是直接取的值。

    三、RequestBuilder类

    通过字面大家就能猜到了他是一个Request的builder类。这个Request是okhttp3.Request。

    (一) 看源码

    (1)、大体上浏览源码

    老规矩,先上源码

    final class RequestBuilder {
      private static final char[] HEX_DIGITS =
          { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
      private static final String PATH_SEGMENT_ALWAYS_ENCODE_SET = " \"<>^`{}|\\?#";
    
      private final String method;
    
      private final HttpUrl baseUrl;
      private String relativeUrl;
      private HttpUrl.Builder urlBuilder;
    
      private final Request.Builder requestBuilder;
      private MediaType contentType;
    
      private final boolean hasBody;
      private MultipartBody.Builder multipartBuilder;
      private FormBody.Builder formBuilder;
      private RequestBody body;
    
      RequestBuilder(String method, HttpUrl baseUrl, String relativeUrl, Headers headers,
          MediaType contentType, boolean hasBody, boolean isFormEncoded, boolean isMultipart) {
        this.method = method;
        this.baseUrl = baseUrl;
        this.relativeUrl = relativeUrl;
        this.requestBuilder = new Request.Builder();
        this.contentType = contentType;
        this.hasBody = hasBody;
    
        if (headers != null) {
          requestBuilder.headers(headers);
        }
    
        if (isFormEncoded) {
          // Will be set to 'body' in 'build'.
          formBuilder = new FormBody.Builder();
        } else if (isMultipart) {
          // Will be set to 'body' in 'build'.
          multipartBuilder = new MultipartBody.Builder();
          multipartBuilder.setType(MultipartBody.FORM);
        }
      }
    
      void setRelativeUrl(Object relativeUrl) {
        if (relativeUrl == null) throw new NullPointerException("@Url parameter is null.");
        this.relativeUrl = relativeUrl.toString();
      }
    
      void addHeader(String name, String value) {
        if ("Content-Type".equalsIgnoreCase(name)) {
          MediaType type = MediaType.parse(value);
          if (type == null) {
            throw new IllegalArgumentException("Malformed content type: " + value);
          }
          contentType = type;
        } else {
          requestBuilder.addHeader(name, value);
        }
      }
    
      void addPathParam(String name, String value, boolean encoded) {
        if (relativeUrl == null) {
          // The relative URL is cleared when the first query parameter is set.
          throw new AssertionError();
        }
        relativeUrl = relativeUrl.replace("{" + name + "}", canonicalizeForPath(value, encoded));
      }
    
      private static String canonicalizeForPath(String input, boolean alreadyEncoded) {
        int codePoint;
        for (int i = 0, limit = input.length(); i < limit; i += Character.charCount(codePoint)) {
          codePoint = input.codePointAt(i);
          if (codePoint < 0x20 || codePoint >= 0x7f
              || PATH_SEGMENT_ALWAYS_ENCODE_SET.indexOf(codePoint) != -1
              || (!alreadyEncoded && (codePoint == '/' || codePoint == '%'))) {
            // Slow path: the character at i requires encoding!
            Buffer out = new Buffer();
            out.writeUtf8(input, 0, i);
            canonicalizeForPath(out, input, i, limit, alreadyEncoded);
            return out.readUtf8();
          }
        }
    
        // Fast path: no characters required encoding.
        return input;
      }
    
      private static void canonicalizeForPath(Buffer out, String input, int pos, int limit,
          boolean alreadyEncoded) {
        Buffer utf8Buffer = null; // Lazily allocated.
        int codePoint;
        for (int i = pos; i < limit; i += Character.charCount(codePoint)) {
          codePoint = input.codePointAt(i);
          if (alreadyEncoded
              && (codePoint == '\t' || codePoint == '\n' || codePoint == '\f' || codePoint == '\r')) {
            // Skip this character.
          } else if (codePoint < 0x20 || codePoint >= 0x7f
              || PATH_SEGMENT_ALWAYS_ENCODE_SET.indexOf(codePoint) != -1
              || (!alreadyEncoded && (codePoint == '/' || codePoint == '%'))) {
            // Percent encode this character.
            if (utf8Buffer == null) {
              utf8Buffer = new Buffer();
            }
            utf8Buffer.writeUtf8CodePoint(codePoint);
            while (!utf8Buffer.exhausted()) {
              int b = utf8Buffer.readByte() & 0xff;
              out.writeByte('%');
              out.writeByte(HEX_DIGITS[(b >> 4) & 0xf]);
              out.writeByte(HEX_DIGITS[b & 0xf]);
            }
          } else {
            // This character doesn't need encoding. Just copy it over.
            out.writeUtf8CodePoint(codePoint);
          }
        }
      }
    
      void addQueryParam(String name, String value, boolean encoded) {
        if (relativeUrl != null) {
          // Do a one-time combination of the built relative URL and the base URL.
          urlBuilder = baseUrl.newBuilder(relativeUrl);
          if (urlBuilder == null) {
            throw new IllegalArgumentException(
                "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
          }
          relativeUrl = null;
        }
    
        if (encoded) {
          urlBuilder.addEncodedQueryParameter(name, value);
        } else {
          urlBuilder.addQueryParameter(name, value);
        }
      }
    
      void addFormField(String name, String value, boolean encoded) {
        if (encoded) {
          formBuilder.addEncoded(name, value);
        } else {
          formBuilder.add(name, value);
        }
      }
    
      void addPart(Headers headers, RequestBody body) {
        multipartBuilder.addPart(headers, body);
      }
    
      void addPart(MultipartBody.Part part) {
        multipartBuilder.addPart(part);
      }
    
      void setBody(RequestBody body) {
        this.body = body;
      }
    
      Request build() {
        HttpUrl url;
        HttpUrl.Builder urlBuilder = this.urlBuilder;
        if (urlBuilder != null) {
          url = urlBuilder.build();
        } else {
          // No query parameters triggered builder creation, just combine the relative URL and base URL.
          url = baseUrl.resolve(relativeUrl);
          if (url == null) {
            throw new IllegalArgumentException(
                "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
          }
        }
    
        RequestBody body = this.body;
        if (body == null) {
          // Try to pull from one of the builders.
          if (formBuilder != null) {
            body = formBuilder.build();
          } else if (multipartBuilder != null) {
            body = multipartBuilder.build();
          } else if (hasBody) {
            // Body is absent, make an empty body.
            body = RequestBody.create(null, new byte[0]);
          }
        }
    
        MediaType contentType = this.contentType;
        if (contentType != null) {
          if (body != null) {
            body = new ContentTypeOverridingRequestBody(body, contentType);
          } else {
            requestBuilder.addHeader("Content-Type", contentType.toString());
          }
        }
    
        return requestBuilder
            .url(url)
            .method(method, body)
            .build();
      }
    
      private static class ContentTypeOverridingRequestBody extends RequestBody {
        private final RequestBody delegate;
        private final MediaType contentType;
    
        ContentTypeOverridingRequestBody(RequestBody delegate, MediaType contentType) {
          this.delegate = delegate;
          this.contentType = contentType;
        }
    
        @Override public MediaType contentType() {
          return contentType;
        }
    
        @Override public long contentLength() throws IOException {
          return delegate.contentLength();
        }
    
        @Override public void writeTo(BufferedSink sink) throws IOException {
          delegate.writeTo(sink);
        }
      }
    }
    

    简单的源码,我们可以轻易得出以下结论

    • 这个类既不是public的也不是private的,所以只能包内引用。
    • 这个类是final,所以没有子类
    • 这个有一个静态内部类ContentTypeOverridingRequestBody
    • RequestBuilder只有一个构造函数,既不是public,也不是private,没有无参的构造函数。
    • 有两个常量char[] HEX_DIGITS和String PATH_SEGMENT_ALWAYS_ENCODE_SET
    (2)、变量分析
      //请求类型,post或者get
      private final String method;
       //Http的url  根地址
      private final HttpUrl baseUrl;
       //相对路径的url,对应的是具体的接口
      private String relativeUrl;
       //HttpUrl的Builder
      private HttpUrl.Builder urlBuilder;
      //okHttp3里面的Request.Builder
      private final Request.Builder requestBuilder;
      // MediaType 也是okHttp3里面的MediaTyep。MediaType即是Internet Media Type,互联网媒体类型;也叫做MIME类型,在http协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息。
      private MediaType contentType;
      // 布尔类型,代表都是有body
      private final boolean hasBody;
       //okHttp3里面的MultipartBody的builder
      private MultipartBody.Builder multipartBuilder;
      //okHttp3里面的FormBody的builder
      private FormBody.Builder formBuilder;
      //okHttp3里面的RequestBody
      private RequestBody body;
    

    我基本上每个变量都给注释了。下面我来研究下构造函数

    (2)、构造函数分析

    看下代码

    RequestBuilder(String method, HttpUrl baseUrl, String relativeUrl, Headers headers,
          MediaType contentType, boolean hasBody, boolean isFormEncoded, boolean isMultipart) {
        this.method = method;
        this.baseUrl = baseUrl;
        this.relativeUrl = relativeUrl;
        this.requestBuilder = new Request.Builder();
        this.contentType = contentType;
        this.hasBody = hasBody;
    
        if (headers != null) {
          requestBuilder.headers(headers);
        }
    
        if (isFormEncoded) {
          // Will be set to 'body' in 'build'.
          formBuilder = new FormBody.Builder();
        } else if (isMultipart) {
          // Will be set to 'body' in 'build'.
          multipartBuilder = new MultipartBody.Builder();
          multipartBuilder.setType(MultipartBody.FORM);
        }
      }
    

    构造函数很简单,就是字段赋值,最后判断是 表单 提交还是 文件 上传,如果是文件上传,则设置类型。

    (3)、相关的set方法分析

    里面有什么类似set的方法,我们这里一次性说下

      void setRelativeUrl(Object relativeUrl) {
        if (relativeUrl == null) throw new NullPointerException("@Url parameter is null.");
        this.relativeUrl = relativeUrl.toString();
      }
      void addHeader(String name, String value) {
        if ("Content-Type".equalsIgnoreCase(name)) {
          MediaType type = MediaType.parse(value);
          if (type == null) {
            throw new IllegalArgumentException("Malformed content type: " + value);
          }
          contentType = type;
        } else {
          requestBuilder.addHeader(name, value);
        }
      }
    
      void addPathParam(String name, String value, boolean encoded) {
        if (relativeUrl == null) {
          // The relative URL is cleared when the first query parameter is set.
          throw new AssertionError();
        }
        relativeUrl = relativeUrl.replace("{" + name + "}", canonicalizeForPath(value, encoded));
      }
    
    void addQueryParam(String name, String value, boolean encoded) {
        if (relativeUrl != null) {
          // Do a one-time combination of the built relative URL and the base URL.
          urlBuilder = baseUrl.newBuilder(relativeUrl);
          if (urlBuilder == null) {
            throw new IllegalArgumentException(
                "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
          }
          relativeUrl = null;
        }
    
        if (encoded) {
          urlBuilder.addEncodedQueryParameter(name, value);
        } else {
          urlBuilder.addQueryParameter(name, value);
        }
      }
    
      void addFormField(String name, String value, boolean encoded) {
        if (encoded) {
          formBuilder.addEncoded(name, value);
        } else {
          formBuilder.add(name, value);
        }
      }
    
      void addPart(Headers headers, RequestBody body) {
        multipartBuilder.addPart(headers, body);
      }
    
      void addPart(MultipartBody.Part part) {
        multipartBuilder.addPart(part);
      }
    
      void setBody(RequestBody body) {
        this.body = body;
      }
    

    相关方法分析

    • setRelativeUrl:设置相对路径的url
    • addHeader:添加请求头
    • addPathParam:添加PathParam参数
    • addQueryParam:添加请求参数,如果是GET方法,直接拼接在相对路径上,如果是post方式则直接放到消息体,这里面其实通过okHttp3的HttpUrl.Builder来实现的。
    • addFormField:添加表单,key-value键值对的形式
    • addPart:这个方法有两个重载,一个是根据header和body来添加MultipartBody,另外一个是直接添加MultipartBody
    • setBody:设置请求的body
    (3)、build()方法分析

    build()主要就是生成一个用于okHttp请求的request,一起看下源码

    Request build() {
        HttpUrl url;
        HttpUrl.Builder urlBuilder = this.urlBuilder;
        //初始化url
        if (urlBuilder != null) {
          url = urlBuilder.build();
        } else {
          // No query parameters triggered builder creation, just combine the relative URL and base URL.
          url = baseUrl.resolve(relativeUrl);
          if (url == null) {
            throw new IllegalArgumentException(
                "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
          }
        }
    
        RequestBody body = this.body;
        //如果没有body
        if (body == null) {
          // Try to pull from one of the builders.
          if (formBuilder != null) {
            body = formBuilder.build();
          } else if (multipartBuilder != null) {
            body = multipartBuilder.build();
          } else if (hasBody) {
            // Body is absent, make an empty body.
            body = RequestBody.create(null, new byte[0]);
          }
        }
        //设置类型
        MediaType contentType = this.contentType;
        if (contentType != null) {
          if (body != null) {
            body = new ContentTypeOverridingRequestBody(body, contentType);
          } else {
            requestBuilder.addHeader("Content-Type", contentType.toString());
          }
        }
        //返回request
        return requestBuilder
            .url(url)
            .method(method, body)
            .build();
      }
    
    (4)、静态内部类ContentTypeOverridingRequestBody分析

    代码很少,直接看源码

      private static class ContentTypeOverridingRequestBody extends RequestBody {
        private final RequestBody delegate;
        private final MediaType contentType;
    
        ContentTypeOverridingRequestBody(RequestBody delegate, MediaType contentType) {
          this.delegate = delegate;
          this.contentType = contentType;
        }
    
        @Override public MediaType contentType() {
          return contentType;
        }
    
        @Override public long contentLength() throws IOException {
          return delegate.contentLength();
        }
    
        @Override public void writeTo(BufferedSink sink) throws IOException {
          delegate.writeTo(sink);
        }
      }
    

    看源码得出如下结论

    • ContentTypeOverridingRequestBody是RequestBody的实现类。
    • ContentTypeOverridingRequestBody其实是一个代理类,真正的body是delegate。

    PS:还有两个静态方法是给Patch请求参数,规范化的,没什么好讲的。

    (二) 总结

    RequestBuilder这个类,代码很简单,主要就是用于创建一个okHttp的Request,里面有很多方法用于设置Request的一些参数。

    四、Response类

    这个类很简单,代码也才100多行,看名字,就是会知道是一个"响应"。老规矩,看下源码:

    (一)、源码分析

    /** An HTTP response. */
    public final class Response<T> {
      /** Create a synthetic successful response with {@code body} as the deserialized body. */
      public static <T> Response<T> success(T body) {
        return success(body, new okhttp3.Response.Builder() //
            .code(200)
            .message("OK")
            .protocol(Protocol.HTTP_1_1)
            .request(new Request.Builder().url("http://localhost/").build())
            .build());
      }
    
      /**
       * Create a synthetic successful response using {@code headers} with {@code body} as the
       * deserialized body.
       */
      public static <T> Response<T> success(T body, Headers headers) {
        if (headers == null) throw new NullPointerException("headers == null");
        return success(body, new okhttp3.Response.Builder() //
            .code(200)
            .message("OK")
            .protocol(Protocol.HTTP_1_1)
            .headers(headers)
            .request(new Request.Builder().url("http://localhost/").build())
            .build());
      }
    
      /**
       * Create a successful response from {@code rawResponse} with {@code body} as the deserialized
       * body.
       */
      public static <T> Response<T> success(T body, okhttp3.Response rawResponse) {
        if (rawResponse == null) throw new NullPointerException("rawResponse == null");
        if (!rawResponse.isSuccessful()) {
          throw new IllegalArgumentException("rawResponse must be successful response");
        }
        return new Response<>(rawResponse, body, null);
      }
    
      /**
       * Create a synthetic error response with an HTTP status code of {@code code} and {@code body}
       * as the error body.
       */
      public static <T> Response<T> error(int code, ResponseBody body) {
        if (code < 400) throw new IllegalArgumentException("code < 400: " + code);
        return error(body, new okhttp3.Response.Builder() //
            .code(code)
            .protocol(Protocol.HTTP_1_1)
            .request(new Request.Builder().url("http://localhost/").build())
            .build());
      }
    
      /** Create an error response from {@code rawResponse} with {@code body} as the error body. */
      public static <T> Response<T> error(ResponseBody body, okhttp3.Response rawResponse) {
        if (body == null) throw new NullPointerException("body == null");
        if (rawResponse == null) throw new NullPointerException("rawResponse == null");
        if (rawResponse.isSuccessful()) {
          throw new IllegalArgumentException("rawResponse should not be successful response");
        }
        return new Response<>(rawResponse, null, body);
      }
    
      private final okhttp3.Response rawResponse;
      private final T body;
      private final ResponseBody errorBody;
    
      private Response(okhttp3.Response rawResponse, T body, ResponseBody errorBody) {
        this.rawResponse = rawResponse;
        this.body = body;
        this.errorBody = errorBody;
      }
    
      /** The raw response from the HTTP client. */
      public okhttp3.Response raw() {
        return rawResponse;
      }
    
      /** HTTP status code. */
      public int code() {
        return rawResponse.code();
      }
    
      /** HTTP status message or null if unknown. */
      public String message() {
        return rawResponse.message();
      }
    
      /** HTTP headers. */
      public Headers headers() {
        return rawResponse.headers();
      }
    
      /** Returns true if {@link #code()} is in the range [200..300). */
      public boolean isSuccessful() {
        return rawResponse.isSuccessful();
      }
    
      /** The deserialized response body of a {@linkplain #isSuccessful() successful} response. */
      public T body() {
        return body;
      }
    
      /** The raw response body of an {@linkplain #isSuccessful() unsuccessful} response. */
      public ResponseBody errorBody() {
        return errorBody;
      }
    
      @Override public String toString() {
        return rawResponse.toString();
      }
    }
    

    其实通过类的注释,大家就知道这是一个HTTP的响应。通过阅读这个类的源码,我们可以获取如下信息:

    • Response类是final,无子类。
    • Response类就一个构造函数,还是private的。
    • Response类含有三个成员变量,均是是在构造的时候赋值的。
    • Response类其中的一个成员变量是
    • 有一些关于响应的get方法,但是其实均是调用rawResponse的自己对应的方法rawResponse,它的类型是okhttp3.Response。
    • 有5个静态函数用于获取一个Response的实例

    (二)、如何获取Response的实例

    由于Response的构造方法是private,所以要想获取Response必须通过他的5个静态方法。那我们来以来了解下这5个静态方法

    1、success(T body, okhttp3.Response rawResponse)方法分析

    为什么先看这个方法,因为其他两个成功静态方法最后都调用了这个方法,那么我们来先看下源码

      /**
       * Create a successful response from {@code rawResponse} with {@code body} as the deserialized
       * body.
       */
      public static <T> Response<T> success(T body, okhttp3.Response rawResponse) {
        if (rawResponse == null) throw new NullPointerException("rawResponse == null");
        if (!rawResponse.isSuccessful()) {
          throw new IllegalArgumentException("rawResponse must be successful response");
        }
        return new Response<>(rawResponse, body, null);
      }
    

    先看一下方法注释:

    通过rawResponse的body作为反序列化的输入来创建一个成功的Retrofit的响应Response。

    PS:这里的rawResponse的类型是okhttp3.Response,这个类里面一共有两个Response,一个是Retrofit的Response一个是okhttp3.Response。大家千万别弄混了。

    这个方法内容很简单,首先判断rawResponse不能为null,否则抛异常,然后直接由把传进来的两个参数body和rawResponse作为参数,构造一个Retrofit的Response。而第三个参数代表的是 "错误" 的消息体,这个事成功的响应,所以这里第三个参数是null。

    2、public static <T> Response<T> success(T body) 方法分析

    先看源码

      /** Create a synthetic successful response with {@code body} as the deserialized body. */
      public static <T> Response<T> success(T body) {
        return success(body, new okhttp3.Response.Builder() //
            .code(200)
            .message("OK")
            .protocol(Protocol.HTTP_1_1)
            .request(new Request.Builder().url("http://localhost/").build())
            .build());
      }
    

    先简单翻一下方法的注释:
    通过使用响应体(body)的反序列化来 "合成" 一个 "成功的" 响应(response)。首先 new okhttp3.Response.Builder(),然后设置相关参数,最后在调用.build()产生一个okhttp3.Response,作为入参,调入自己两个入参的sucess静态方法。

    3、Response<T> success(T body, Headers headers)
      /**
       * Create a synthetic successful response using {@code headers} with {@code body} as the
       * deserialized body.
       */
      public static <T> Response<T> success(T body, Headers headers) {
        if (headers == null) throw new NullPointerException("headers == null");
        return success(body, new okhttp3.Response.Builder() //
            .code(200)
            .message("OK")
            .protocol(Protocol.HTTP_1_1)
            .headers(headers)
            .request(new Request.Builder().url("http://localhost/").build())
            .build());
      }
    

    先看下方法的注释:

    通过使用body和headers作为输入来创建一个合成的成功的response响应。

    它和上面的区别就是这个方法多了一个入参headers,并且在okhttp3.Response.Builder的headers()set进去的。

    4、Response<T> error(ResponseBody body, okhttp3.Response rawResponse)
      /** Create an error response from {@code rawResponse} with {@code body} as the error body. */
      public static <T> Response<T> error(ResponseBody body, okhttp3.Response rawResponse) {
        if (body == null) throw new NullPointerException("body == null");
        if (rawResponse == null) throw new NullPointerException("rawResponse == null");
        if (rawResponse.isSuccessful()) {
          throw new IllegalArgumentException("rawResponse should not be successful response");
        }
        return new Response<>(rawResponse, null, body);
      }
    

    翻译一下注释:

    通过使用body和rawResponse作为输入,来创建一个错误的响应。

    首先,做了非空检查;然后是错误检查,因为是错误的响应,所以rawResponse.isSuccessful()是false;最后new Response返回,new Response的入参是rawResponse,null,body。

    5、Response<T> error(int code, ResponseBody body)

    看下源码

    /**
       * Create a synthetic error response with an HTTP status code of {@code code} and {@code body}
       * as the error body.
       */
      public static <T> Response<T> error(int code, ResponseBody body) {
        if (code < 400) throw new IllegalArgumentException("code < 400: " + code);
        return error(body, new okhttp3.Response.Builder() //
            .code(code)
            .protocol(Protocol.HTTP_1_1)
            .request(new Request.Builder().url("http://localhost/").build())
            .build());
      }
    

    先看下类注释:

    通过使用code和body作为输入,来创建一个合成的错误的Response(响应体)。

    首先new了一个okhttp3.Response.Builder,然后设置一些属性,
    然后把这个okhttp3.Response.Builder作为参数,调用上面的error方法。

    (三)、总结

    Response是Retrofit的内"设定"的的响应,由于Response的构造方式是private的,所以创建则是由success和error五个静态方法来获取Response,但是Response的一些方法其实本质是调用的是rawResponse的一些方法。

    五 OkHttpCall

    (一)、OkHttpCall是什么?

    从类名选择上,我的第一反应是okHttp的call的包装类,但是实际是的确是这样的,ok大家怀着这样的一个问题一起来阅读下源码:

    (二) 源码阅读:

    final class OkHttpCall<T> implements Call<T> {
      private final ServiceMethod<T, ?> serviceMethod;
      private final Object[] args;
    
      private volatile boolean canceled;
    
      // All guarded by this.
      private okhttp3.Call rawCall;
      private Throwable creationFailure; // Either a RuntimeException or IOException.
      private boolean executed;
    
      OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {
        this.serviceMethod = serviceMethod;
        this.args = args;
      }
    
      @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
      @Override public OkHttpCall<T> clone() {
        return new OkHttpCall<>(serviceMethod, args);
      }
    
      @Override public synchronized Request request() {
        okhttp3.Call call = rawCall;
        if (call != null) {
          return call.request();
        }
        if (creationFailure != null) {
          if (creationFailure instanceof IOException) {
            throw new RuntimeException("Unable to create request.", creationFailure);
          } else {
            throw (RuntimeException) creationFailure;
          }
        }
        try {
          return (rawCall = createRawCall()).request();
        } catch (RuntimeException e) {
          creationFailure = e;
          throw e;
        } catch (IOException e) {
          creationFailure = e;
          throw new RuntimeException("Unable to create request.", e);
        }
      }
    
      @Override public void enqueue(final Callback<T> callback) {
        if (callback == null) throw new NullPointerException("callback == null");
    
        okhttp3.Call call;
        Throwable failure;
    
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already executed.");
          executed = true;
    
          call = rawCall;
          failure = creationFailure;
          if (call == null && failure == null) {
            try {
              call = rawCall = createRawCall();
            } catch (Throwable t) {
              failure = creationFailure = t;
            }
          }
        }
    
        if (failure != null) {
          callback.onFailure(this, failure);
          return;
        }
    
        if (canceled) {
          call.cancel();
        }
    
        call.enqueue(new okhttp3.Callback() {
          @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
              throws IOException {
            Response<T> response;
            try {
              response = parseResponse(rawResponse);
            } catch (Throwable e) {
              callFailure(e);
              return;
            }
            callSuccess(response);
          }
    
          @Override public void onFailure(okhttp3.Call call, IOException e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
    
          private void callFailure(Throwable e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
    
          private void callSuccess(Response<T> response) {
            try {
              callback.onResponse(OkHttpCall.this, response);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
        });
      }
    
      @Override public synchronized boolean isExecuted() {
        return executed;
      }
    
      @Override public Response<T> execute() throws IOException {
        okhttp3.Call call;
    
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already executed.");
          executed = true;
    
          if (creationFailure != null) {
            if (creationFailure instanceof IOException) {
              throw (IOException) creationFailure;
            } else {
              throw (RuntimeException) creationFailure;
            }
          }
    
          call = rawCall;
          if (call == null) {
            try {
              call = rawCall = createRawCall();
            } catch (IOException | RuntimeException e) {
              creationFailure = e;
              throw e;
            }
          }
        }
    
        if (canceled) {
          call.cancel();
        }
    
        return parseResponse(call.execute());
      }
    
      private okhttp3.Call createRawCall() throws IOException {
        Request request = serviceMethod.toRequest(args);
        okhttp3.Call call = serviceMethod.callFactory.newCall(request);
        if (call == null) {
          throw new NullPointerException("Call.Factory returned null.");
        }
        return call;
      }
    
      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();
    
        int code = rawResponse.code();
        if (code < 200 || code >= 300) {
          try {
            // Buffer the entire body to avoid future I/O.
            ResponseBody bufferedBody = Utils.buffer(rawBody);
            return Response.error(bufferedBody, rawResponse);
          } finally {
            rawBody.close();
          }
        }
    
        if (code == 204 || code == 205) {
          rawBody.close();
          return Response.success(null, rawResponse);
        }
    
        ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
        try {
          T body = serviceMethod.toResponse(catchingBody);
          return Response.success(body, rawResponse);
        } catch (RuntimeException e) {
          // If the underlying source threw an exception, propagate that rather than indicating it was
          // a runtime exception.
          catchingBody.throwIfCaught();
          throw e;
        }
      }
    
      public void cancel() {
        canceled = true;
    
        okhttp3.Call call;
        synchronized (this) {
          call = rawCall;
        }
        if (call != null) {
          call.cancel();
        }
      }
    
      @Override public boolean isCanceled() {
        if (canceled) {
          return true;
        }
        synchronized (this) {
          return rawCall != null && rawCall.isCanceled();
        }
      }
    
      static final class NoContentResponseBody extends ResponseBody {
        private final MediaType contentType;
        private final long contentLength;
    
        NoContentResponseBody(MediaType contentType, long contentLength) {
          this.contentType = contentType;
          this.contentLength = contentLength;
        }
    
        @Override public MediaType contentType() {
          return contentType;
        }
    
        @Override public long contentLength() {
          return contentLength;
        }
    
        @Override public BufferedSource source() {
          throw new IllegalStateException("Cannot read raw response body of a converted body.");
        }
      }
    
      static final class ExceptionCatchingRequestBody extends ResponseBody {
        private final ResponseBody delegate;
        IOException thrownException;
    
        ExceptionCatchingRequestBody(ResponseBody delegate) {
          this.delegate = delegate;
        }
    
        @Override public MediaType contentType() {
          return delegate.contentType();
        }
    
        @Override public long contentLength() {
          return delegate.contentLength();
        }
    
        @Override public BufferedSource source() {
          return Okio.buffer(new ForwardingSource(delegate.source()) {
            @Override public long read(Buffer sink, long byteCount) throws IOException {
              try {
                return super.read(sink, byteCount);
              } catch (IOException e) {
                thrownException = e;
                throw e;
              }
            }
          });
        }
    
        @Override public void close() {
          delegate.close();
        }
    
        void throwIfCaught() throws IOException {
          if (thrownException != null) {
            throw thrownException;
          }
        }
      }
    }
    

    大家先粗略的看下,后续再一个接着一个去慢慢讲解,读完源码有什么感觉?

    1、源码初读

    我读源码可以获取如下信息

    • OkHttpCall<T>是final的,是不允许继承的
    • OkHttpCall<T>是实现的retrofit2.Call<T>接口
    • 有一个两个参数的构造函数,但是不是public,意味着只能包内掉用,外部无法调用。
    • 有两个静态内部类NoContentResponseBody和ExceptionCatchingRequestBody
    • 有个private的成员变量canceled是** "volatile" **的,估计会有多线程对其操作

    初步阅读源码我能得到这么多的信息,那我们再来仔细的阅读下源码

    2、分析成员变量

    OkHttpCall<T> 成员变量很少,我直接在源码上注释了

      //方法处理类,后面详解讲解,大家这里有个印象即可
      private final ServiceMethod<T, ?> serviceMethod;
      //和方法处理类一样,其实是调用方法的入参,大家先知道就可以,后期会详细讲解。
      private final Object[] args;
      // 判断 是否已经取消了。
      //volatile,如果有同学不清楚,请直接百度下,这个关键字还是很重要的,主要用于多线程使用的背景下。
      private volatile boolean canceled;
      // All guarded by this.
      //真正的okhttp3.Call,真正的请求
      private okhttp3.Call rawCall;
      // 异常,包括IO和运行时异常
      private Throwable creationFailure; // Either a RuntimeException or IOException.
      //是否已经启动
      private boolean executed;
    
    3、分析构造函数
      OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {
        this.serviceMethod = serviceMethod;
        this.args = args;
      }
    

    构造函数很简单,需要传入一个ServiceMethod和args,然后进行赋值,如果大家对泛型认识不是很熟练,这里是可以知道ServiceMethod<T, ?>里面的第一个泛型的类型和OkHttpCall<T>是同一个类型即可。

    4、静态内部类分析之NoContentResponseBody

    看类名,我们就知道是一个空的响应体,那我们看下源码

      static final class NoContentResponseBody extends ResponseBody {
        private final MediaType contentType;
        private final long contentLength;
    
        NoContentResponseBody(MediaType contentType, long contentLength) {
          this.contentType = contentType;
          this.contentLength = contentLength;
        }
    
        @Override public MediaType contentType() {
          return contentType;
        }
    
        @Override public long contentLength() {
          return contentLength;
        }
    
        @Override public BufferedSource source() {
          throw new IllegalStateException("Cannot read raw response body of a converted body.");
        }
      }
    

    通过源码我们可知

    • 这个NoContentResponseBody类是final的,不允许继承。
    • 这个NoContentResponseBody类是ResponseBody的子类。
    • 这个类有两个属性contentType,contentLength,且均是final,构造时候赋值之后,就不能变更了
    • 这个类不能读取,读取就会报错

    NoContentResponseBody这个类比较简单,就是没有body内容,但是有contentType和contentLength,这时候我们就像那body去哪里了?难道body被"吃"了,ok这里留个一悬念,大家把这个问题,记住,后面我会一一解答的。

    5、静态内部类分析之ExceptionCatchingRequestBody

    通过类名,我们大概可以分析好像是一个请求体异常捕获的类了,是不是这样?我们还是看一下源码

      static final class ExceptionCatchingRequestBody extends ResponseBody {
        private final ResponseBody delegate;
        IOException thrownException;
    
        ExceptionCatchingRequestBody(ResponseBody delegate) {
          this.delegate = delegate;
        }
    
        @Override public MediaType contentType() {
          return delegate.contentType();
        }
    
        @Override public long contentLength() {
          return delegate.contentLength();
        }
    
        @Override public BufferedSource source() {
          return Okio.buffer(new ForwardingSource(delegate.source()) {
            @Override public long read(Buffer sink, long byteCount) throws IOException {
              try {
                return super.read(sink, byteCount);
              } catch (IOException e) {
                thrownException = e;
                throw e;
              }
            }
          });
        }
    
        @Override public void close() {
          delegate.close();
        }
    
        void throwIfCaught() throws IOException {
          if (thrownException != null) {
            throw thrownException;
          }
        }
      }
    

    通过读取源码我们可以获取如下信息:

    • ExceptionCatchingRequestBody同样是final的不允许继承
    • ExceptionCatchingRequestBody是继承ResponseBody
    • ExceptionCatchingRequestBody有个属性是okhttp3.ResponseBody 类型的,不是retrofit2.Response.且这个属性是final的,在构造函数里面被赋值。
    • thrownException这个属性在构造的时候没有被赋值,那什么时候被复制的那? 其实在source()方法里面有个try{}catch捕获异常,当出现异常的时候就把异常赋值给thrownException。
    • 无论是contentType()还是contentLength()或是close(),其实内部调用是delegate对应的方法。所以可以看出ExceptionCatchingRequestBody其实也是一个包括类。
    6、具体的方法分析
    6.1、clone()方法

    我们知道这个是实现retrofit2.Call的抽象方法,主要用于克隆一个call

      @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
      @Override public OkHttpCall<T> clone() {
        return new OkHttpCall<>(serviceMethod, args);
      }
    

    这个clone()方法很简单,就是同样的参数直接new了一个OkHttpCall对象

    6.3、request()方法
      @Override public synchronized Request request() {
        okhttp3.Call call = rawCall;
        //先判断rawCall是否为null,如果不为null,之前new过,则直接返回
        if (call != null) {
          return call.request();
        }
        //判断是不是存在异常,如果存在异常,则直接抛出异常
        if (creationFailure != null) {
          if (creationFailure instanceof IOException) {
            throw new RuntimeException("Unable to create request.", creationFailure);
          } else {
            throw (RuntimeException) creationFailure;
          }
        }
         //通过createRawCall()来创建一个新的okhttp3.Call call
        try {
          return (rawCall = createRawCall()).request();
        } catch (RuntimeException e) {
          creationFailure = e;
          throw e;
        } catch (IOException e) {
          creationFailure = e;
          throw new RuntimeException("Unable to create request.", e);
        }
      }
    

    大体流程如下:

    • 1、判断rawCall是否已经存在,如果存在直接调用rawCall的request()
    • 2、如果rawCall不为空,再判断是不是因为之前创建的时候出现过异常导致rawCall不能被创建,所以做了异常判断,如果有异常说明之前也是创建过,只不过创建失败了,直接抛出异常。
    • 3、如果rawCall为null,并且没有异常,则肯定是首次创建,然后调用createRawCall()创建一个okhttp3.Call 。

    下面就让我们了解下createRawCall()方法

    6.4、createRawCall()方法
      private okhttp3.Call createRawCall() throws IOException {
        Request request = serviceMethod.toRequest(args);
        okhttp3.Call call = serviceMethod.callFactory.newCall(request);
        if (call == null) {
          throw new NullPointerException("Call.Factory returned null.");
        }
        return call;
      }
    

    大家发现是通过ServiceMethod类的toRequest方法,入参是args,就可以获取一个Request了。然后调用ServiceMethod类的属性callFactory的newCall方法传入一个request就可以获取一个 okhttp3.Cal。那ServiceMothod是什么?大家别着急我们马上就要讲解这个类了

    6.5、execute() 方法

    我们知道这个是实现retrofit2.Call的抽象方法,主要用于发起同步请求

      @Override public Response<T> execute() throws IOException {
        okhttp3.Call call;
    
        synchronized (this) {
          //如果已经启动了/执行了,就不能重复启动/执行
          if (executed) throw new IllegalStateException("Already executed.");
          executed = true;
          //如果有异常,则说明之前出现异常,直接抛出异常
          if (creationFailure != null) {
            if (creationFailure instanceof IOException) {
              throw (IOException) creationFailure;
            } else {
              throw (RuntimeException) creationFailure;
            }
          }
         
          call = rawCall;
          //如果rawCall为null,则通过createRawCall()方法来获取一个okhttp3.Call对象。
          if (call == null) {
            try {
              call = rawCall = createRawCall();
            } catch (IOException | RuntimeException e) {
              creationFailure = e;
              throw e;
            }
          }
        }
        //如果请求被取消了,则取消请求
        if (canceled) {
          call.cancel();
        }
        //先调用call.execute(),这里补充下call.execute()返回的是okhttp3.Response,然后调用parseResponse()方法。
        return parseResponse(call.execute());
      }
    

    大体流程如下:

    • 1、先判断是否应启动/执行了,如果已经启动/执行,就不能重复启动/执行,直接抛异常
    • 2、判断是否之前出现过异常,如果出现异常则直接抛出
    • 3、判断rawCall是否为null,如果null则调用createRawCall()获取一个okhttp3.Call。
    • 4、判断请求是否已经被取消了,如果已经被取消了,则取消。
    • 5、执行call.execute()方法
    • 6、把all.execute()执行的返回值okhttp3.Response作为入参,再调用parseResponse()方法
    6.5、parseResponse() 方法

    这个方法,看名字就知道是一个解析Response的方法。就是将请求结果反序列化,内部调用ServiceMethod中的responseConverter,也就是配置里的反序列化工具生成JavaBean。

     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.
         //创建一个新的okhttp3.Response,且body是null,但是还是有大小和类型
        rawResponse = rawResponse.newBuilder()
            .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
            .build();
         //获取HTTP的状态码
        int code = rawResponse.code();
         //如果不是成功的HTTP状态码
        if (code < 200 || code >= 300) {
          try {
            // Buffer the entire body to avoid future I/O.
            //获取对应的响应体内容
            ResponseBody bufferedBody = Utils.buffer(rawBody);
            //调用Response的静态方法error来获取一个retrofit2.Response
            return Response.error(bufferedBody, rawResponse);
          } finally {
            rawBody.close();
          }
        }
         //如果HTTP状态码是204或者205则说明没有响应体或者重置内容
        if (code == 204 || code == 205) {
          rawBody.close();
          //调用Response的静态方法success来获取一个retrofit2.Response
          return Response.success(null, rawResponse);
        }
        //new了一个ExceptionCatchingRequestBody对象
        ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
        try {
           //调用serviceMethod的toResponse()的方法可以返回一个T类型的body
          T body = serviceMethod.toResponse(catchingBody);
           //调用Response的静态方法success来获取一个retrofit2.Response
          return Response.success(body, rawResponse);
        } catch (RuntimeException e) {
          // If the underlying source threw an exception, propagate that rather than indicating it was
          // a runtime exception.
          //如果底层的源代码抛出异常,则抛出异常,而不是指示它是一个运行时异常。
          catchingBody.throwIfCaught();
          throw e;
        }
      }
    

    大体流程如下:

    • 1、先获取响应体,存在一个变量rawBody里面
    • 2、通过okhttp3.Response. newBuilder和NoContentResponseBody对象,重新构建一个新的okhttp3.Response给rawResponse
    • 3、获取HTTP状态码
    • 4、处理异常状态码,通过Response.error()方法获取一个Response返回
    • 5、处理状态码204和205状态
    • 6、创建一个ExceptionCatchingRequestBody对象
    • 7、调用serviceMethod.toResponse()方法获取一个类型为T的body对象。
    • 8、把类型为T的body作为入参调用Response.success(body, rawResponse)获取一个对应的retrofit2.Response,并返回。

    大家还记得之前的那个问题吗?NoContentResponseBody里面的body为什么没有内容,其实没有被"吃",而是被提前取出,这样就实现了HTTP 状态码和内容的解耦,厉害啊老铁。

    6.6、enqueue(final Callback<T> callback) 方法

    看名字我会认为是一个异步请求的方法,具体看下代码

     @Override public void enqueue(final Callback<T> callback) {
        if (callback == null) throw new NullPointerException("callback == null");
    
        okhttp3.Call call;
        Throwable failure;
      
        synchronized (this) {
           //检查是否启动/执行过
          if (executed) throw new IllegalStateException("Already executed.");
          executed = true;
    
          call = rawCall;
          failure = creationFailure;
          //判断是否产生过错误
          if (call == null && failure == null) {
            try {
              //创建call
              call = rawCall = createRawCall();
            } catch (Throwable t) {
              failure = creationFailure = t;
            }
          }
        }
    
        if (failure != null) {
          callback.onFailure(this, failure);
          return;
        }
        //判断是否取消
        if (canceled) {
          call.cancel();
        }
        //加入okhttp的请求队列
        call.enqueue(new okhttp3.Callback() {
          @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
              throws IOException {
            Response<T> response;
            try {
              //调用parse方法解析response,进行反序列化,获取对应的JavaBean
              response = parseResponse(rawResponse);
            } catch (Throwable e) {
              callFailure(e);
              return;
            }
            调用callSuccess()方法
            callSuccess(response);
          }
    
          @Override public void onFailure(okhttp3.Call call, IOException e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
          //成功方法
          private void callFailure(Throwable e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
          //失败方法
          private void callSuccess(Response<T> response) {
            try {
              callback.onResponse(OkHttpCall.this, response);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
        });
      }
    

    大体流程如下:

    • 1、检查是否执行过
    • 2、创建rawCall
    • 3、检查是否产生过错误
    • 4、检查是否已经取消
    • 5、将raw加入队列
    • 6、处理回调
    6.7 其他方法

    其他方法比较简单,直接在简单说下

    • isCanceled():判断是否已经被取消
    • cancel():取消请求
    • isExecuted():是否已经执行

    (三) 总结:

    OkHttpCall仅仅是一个包装类,外部使用Retrofit.Call,其实内部调用的是Okhttp3.Call,由OkHttpCall来实现调度。所以对外部来说,无需关心** 网络层 **倒是怎么操作的。

    至此整个OkHttpCall已经介绍完毕了,大家有没有对这个类有更清晰的了解,当担大家也有一些疑惑,比如ServiceMethod的关系,大家别着急,我们现在就来怼一下Retrofit最关键的类之一ServiceMethod,请关注下一篇文章。

    相关文章

      网友评论

      本文标题:Retrofit解析7之相关类解析

      本文链接:https://www.haomeiwen.com/subject/bflvqxtx.html