整体Retrofit内容如下:
- 1、Retrofit解析1之前哨站——理解RESTful
- 2、Retrofit解析2之使用简介
- 3、Retrofit解析3之反射
- 4、Retrofit解析4之注解
- 5、Retrofit解析5之代理设计模式
- 6、Retrofit解析6之面向接口编程
- 7、Retrofit解析7之相关类解析
- 8、Retrofit解析8之核心解析——ServiceMethod及注解1
- 9、Retrofit解析8之核心解析——ServiceMethod及注解2
- 10、Retrofit解析9之流程解析
- 11、Retrofit解析10之感谢
上篇文章讲解了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,请关注下一篇文章。
网友评论