一、Retrofit是什么
官方介绍是这样的
A type-safe HTTP client for Android and Java. 翻译成中文是“适用于 Android 和 Java 的类型安全 HTTP 客户端。”
个人理解,Retrofit就是对OkHttp的一层封装,可以让我们更加简单的发送和解析网络请求。
二、Retrofit如何使用
详细使用建议参考官方文档,这里只作必要的介绍。
step1
首先需要创建一个类似这样的接口类
interface TestService {
@GET("users/{user}/repos")
fun listRepos(@Path("user") user: String): Call<List<Repo>?>
}
解释一下:
可以看到这个接口中有个抽象方法,其方法上添加了@GET注解,并且参数是字符串users/{user}/repos 。
其含义是: 该接口的请求方式为GET,请求的路径为baseurl+"users/{user}/repos",baseurl是retrofit创建的时候设置的,待会儿我们会讲到。
listRepos方法参数user添加了@Path注解,注解参数是字符串“user”。
其含义是:将方法参数中的user变量的内容替换为@Path注解中“users/{user}/repos”的{user},从而实现根据传入的user变量不同,修改path的目的。
返回值Call<List<Repo>?>是Call类型,Call是Retrofit中的类,表示发起请求的对象,其泛型为List<Repo>,这表示这个接口的返回内容会被封装为一个List<Repo>,其中Repo是我们自定义的数据model。
step2
private fun testRetrofit() {
// 通过建造者模式创建Retfotit实例
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build()
val service = retrofit.create(TestService::class.java)
val repos = service.listRepos("hfhuaizhi")
repos.enqueue(object : retrofit2.Callback<List<Repo>?> {
override fun onFailure(call: Call<List<Repo>?>, t: Throwable) {
}
override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) {
Log.e(TAG, "response:${response.body()}")
}
})
}
step2.1
首先可以看到通过建造者模式创建了retrofit实例,其中
baseUrl("https://api.github.com"):设置设置baseUrl,其与我们在@Path注解中传入的参数组成要访问的URL,比如我们step1中的url就是“https://api.github.com/users/{user}/repos”, 其中{user}根据listRepos接口传入的user参数而改变。
addConverterFactory(GsonConverterFactory.create()):设置数据转换器,常规HTTP请求返回的是字符串文本数据,我们通过这个Convert将文本数据解析为我们想要的数据类型。比如在本例子中,“https://api.github.com/users/{user}/repos”返回的是一个json数组,我们用GsonConverter将其直接转换为数据对象。需要注意的是,GsonConverterFactory不在retrofit库中,需要额外引入com.squareup.retrofit2:converter-gson:2.9.0,类似的还有解析xml的converter等等,你也可以自定义converter。
step2.2
接下来通过我们构建出来的retrofit实例的create方法。创建了一个service,其参数是TestService::class.java 其中该方法的目的是创建一个代理的service,用动态代理生成了一个新类,待会儿我们会讲。
step2.3
调用生成的代理类的listRepos方法返回一个call对象
step2.4
调用call的enqueue方法,并在response中接收网络返回结果。
结果输出
2021-12-26 17:17:32.580 15445-15445/com.hfhuaizhi.retrofittest E/hftest: response:[Repo(archive_url=https://api.github.com/repos/hfhuaizhi/ComposeSearchDemo/{archive_format}{/ref}, archived=false, assignees_url=https://api.github.com/repos/hfhuaizhi/ComposeSearchDemo/assignees{/user}, ...省略
三、Retrofit原理解析
首先思考,我们发送一个请求的前提是什么呢,前提必然是是知道要请求的url和参数。
其中baseurl在retrofit实例的创建过程中被设置,path和参数通过接口方法的注解被设置,
所以,retrofit发起网络请求的过程就是:
通过解析接口上的方法注解,获取完整的url,然后通过OkHttp发起请求,并用converter对网络请求结果进行解析。 跟着这个思路,我们来看一下上一节step2中的方法都做了什么。
3.1 retrofit的build
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
}
- 首先对baseUrl判空,
- 如果没设置callFactory的话,会设置一个默认的OkHttpClient,这里我们是没对callFactory设置的,所以用的是默认的OkHttpClient,有需要可以传入一个自定义OkHttpClient,设置想要的拦截器,自定义配置等等。
- 未设置callbackExecutor的话会设置一个默认的callbackExecutor,android默认的executor是
MainThreadExecutor,其内部封装了一个handler,用于将callback回调post到main thread。是的,我们retrofit2.Callback的onResponse和onFailure都是默认在主线程被回调的,而okhttp默认回调在子线程。 - callAdapterFactories是设置callAdapter,可以设置RxJavaAdapter来配合RxJava使用,这里我们没设置callAdapter,使用默认的
DefaultCallAdapterFactory - converterFactories 数据转换器,这里我们设置的是GsonConverter,其内部封装了Gson,用于将json字符串转换为数据对象。
- 这些都设置完成后,返回了一个Retrofit实例
3.2 retrofit.create做了什么
总所周知,接口中的抽象方法是无法被直接调用的,所以我们要想使用listRepos方法发起网络请求,得根据我们定义的TestService接口,生成一个新的实现类,调用这个生成类的listRepos方法来发起网络请求,而retrofit.create就是来生成这个类的,其参数是要代理的类对象,这里我们传入的是TestService::class.java
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
- 首先调用
validateServiceInterface进行参数的合法性校验 - 调用
Proxy.newProxyInstance生成一个service类的代理,这里用到了java动态代理的基础知识,不太了解动态代理的同学可以先简单理解为:生成代理类的所有方法调用都会走到这个invoke回调,我们在这里invoke回调中可以获得所调用方法的注解,返回值等等各种信息,可以对方法进行hook或扩展。在这里因为我们代理的是TestService,其所有方法的返回类型都是Call,所有这里的invoke最终会return一个call对象。
3.3 service.listRepos("hfhuaizhi")做了什么
在3.2节我们知道,service是动态代理生成的TestService接口的代理对象,其listRepos方法调用后,会走到invoke回调,并返回一个call对象,所以我们接下来继续回过头看一下invoke回调做了什么
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
invoke(Object proxy, Method method, @Nullable Object[] args)参数解释:
- proxy,代理对象实例
- method,所调用的方法,此处是Java中的方法对象
- args, 方法参数,一个Object数组 在invoke方法中,进行了这几步操作:
- 判断method在类中声明,而不是在接口中声明的话,直接调用method的invoke。
- 判断method是接口中的默认方法的话,走默认方法的调用,因为在java8中interface里也可以实现方法了。不是默认方法的话,调用loadServiceMethod,方法解析完成后,调用走正常的方法解析和invoke
接下来看一下
loadServiceMethod方法做了什么。
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
- 首先从serviceMethodCache缓存中获取ServiceMethod,获取到的话就直接返回,因为对方法的解析需要通过反射获取方法上的注解,是一个相对耗时的操作,所以加一个缓存是很有必要的。
- 没缓存该method的ServiceMethod的话,就调用ServiceMethod.parseAnnotations来解析method,生成ServiceMethod对象,并将其缓存,为了保证线程安全还加了个双重校验锁。 接下来我们有必要看一下ServiceMethod.parseAnnotations是如何通过method生成一个ServiceMethod对象的,猜测可能是通过读取method上的注解来封装成一个ServiceMethod,我们看看是不是这样(当然是这样)。
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
...
}
ServiceMethod的parseAnnotations方法中又继续调用了RequestFactory.parseAnnotations,我们继续跟进去看RequestFactory.parseAnnotations方法是干嘛的。
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
创建了一个builder,传入的参数是retrofit和method,先看Builder的构造方法,再看build方法。
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
构造方法中,接受了retrofit实例和method,并且通过method.getAnnotations()获取了method上声明的注解,并将其保存在methodAnnotations list中,获取method的参数类型保存在parameterTypes list中,获取参数注解保存在parameterAnnotationsArray list中。
接下来继续看build()方法
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
...
return new RequestFactory(this);
}
为了减少篇幅,省略了一堆不重要的方法,可以看到首先遍历刚构造方法中传入的方法注解list methodAnnotations,调用parseMethodAnnotation对其进行解析,接下来看一下parseMethodAnnotation是怎么对方法进行解析的。
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
果然不出所料,就是通过解析注解来获取请求参数,内容太多,有兴趣的可以自己去看一下。
好了我们再往回走,回到ServiceMethod的parseAnnotations方法,因为我们主要的目的还是看ServiceMethod是如何生成的。
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
...
}
刚RequestFactory.parseAnnotations方法我们已经知道是通过解析method上的注解来生成了一个RequestFactory,接下来又校验了一下方法返回值类型,调用HttpServiceMethod.parseAnnotations方法,传入之前解析好的requestFactory,生成了我们要使用的ServiceMethod。接下来我们继续看HttpServiceMethod.parseAnnotations方法做了什么
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
/**
* Inspects the annotations on an interface method to construct a reusable service method that
* speaks HTTP. This requires potentially-expensive reflection so it is best to build each service
* method only once and reuse it.
*/
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType =
Utils.getParameterLowerBound(
0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(
method,
"'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
...
}
这个方法很长,主要是对method方法的信息再次获取然后封装,根据方法类型返回不同的ServiceMethod
因为我们这个方法不是kotlin的suspend方法,所以最终return一个封装好的CallAdapted,loadServiceMethod就分析完毕了,继续回到代理类的invoke方法。
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
loadServiceMethod后又调用了invoke,经过刚才的分析我们知道了返回的MethodService是CallAdapted,所以我们接下来看一下CallAdapted的invoke
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
...
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
...
}
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
...
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
...
}
可以看到CallAdapted继承自HttpServiceMethod,HttpServiceMethod的invoke方法调用了adapt抽象方法,所以invoke方法调用后最终会调用到CallAdapted的中的adapt方法实现,并且传进去了一个参数call,是OkHttpCall。
其中调用了callAdapter的adapt方法,这个callAdapter是在CallAdapted的构造方法中传进来的,其实就是我们在3.1节所说的默认adapter DefaultCallAdapterFactory的get方法中创建的adapter
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
...
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
}
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
}
...
}
其get方法中返回了一个匿名内部类CallAdapter,内部类的adapt方法会返回一个ExecutorCallbackCall实例,并且构造方法中传入了executor,这个executor就是3.1节所说的MainThreadExecutor,而这个call就是在HttpServiceMethod的invoke方法中new出来的OkHttpCall。
我们一开始就知道调用代理类的listRepos方法后会返回一个Call对象,这个Call的实现类就是ExecutorCallbackCall
到这里service.listRepos("hfhuaizhi")就分析结束了。
最后一步repos.enqueue做了什么
之前我们分析了一大堆,发现都是在封装参数,一直没发起真正的网络请求,那么猜测最后这一步应该就是要发起网络请求了,并回调,解析网络请求结果了吧。
由之前的分析我们知道,这个repos是ExecutorCallbackCall的实例(在我们这个例子中是这样的)。所以接下来我们去看一下ExecutorCallbackCall的enqueue方法。
static final class ExecutorCallbackCall<T> implements Call<T> {
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
...
}
可以看到enqueue又调用了delegate的delegate,这个deletate在上一节中我们知道了就是HttpServiceMethod的invoke方法中new出来的OkHttpCall,所以接下来我们看一下OkHttpCall中的enqueue方法。
final class OkHttpCall<T> implements Call<T> {
...
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
...
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
...
}
可以看到其内封装了一个 okhttp3.Call的call,其enqueue方法会调用OkHttp3的Call的enqueue方法来发起网络请求,并将结果通过callback回调,需要注意的是onResponse回调中的parseResponse方法,因为我们一开始就知道retrofit会直接将请求数据解析为数据model,这个解析的过程就是在此进行的,
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);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
T body = responseConverter.convert(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;
}
}
主要看responseConverter.convert(catchingBody);,这个responseConverter,就是我们一开始设置的GsonConverter,其将body转成数据model,然后将解析好的数据,回调给ExecutorCallbackCall。
我们知道okhttp3的回调是在子线程,所以继续回到ExecutorCallbackCall
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
可以看到其onResponse和onFailure回调中会通过callbackExecutor执行一下,我们在3.1节中知道callbackExecutor是MainThreadExecutor
private static class MainThreadExecutor implements Executor {
final Handler mHandler = new Handler(Looper.getMainLooper());
MainThreadExecutor() {}
@Override
public void execute(@NonNull Runnable command) {
mHandler.post(command);
}
}
其execute方法会将runnable post到主线程。至此分析结束。