本篇内容主要讲解“Retrofit网络请求和响应处理源码分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Retrofit网络请求和响应处理源码分析”吧!
网络请求
在使用 Retrofit 发起网络请求时,我们可以通过定义一个接口并使用 Retrofit 的注解来描述这个接口中的请求,Retrofit 会自动生成一个实现该接口的代理对象。当我们调用这个代理对象的方法时,Retrofit 会根据注解的描述构建一个 Request 对象,并使用 OkHttp 将这个 Request 发送出去。
在 Retrofit 中,我们可以通过
或
Retrofit#execute
方法来发送请求。这两个方法的区别在于,
Retrofit#enqueue
方法会阻塞当前线程直到请求完成,而
execute
方法会将请求加入到 OkHttp 的请求队列中,并在请求完成时通过回调通知我们。
enqueue
我们先来看一下
方法的实现:
execute
public <T> T execute(Call<T> call) throws IOException {
Utils.validateServiceInterface(call.request().tag(), call.request().url().toString());
return (T) callAdapter(call, call.request().tag()).adapt(call).execute();
}
在这个方法中,首先会对接口进行校验,确保这个接口是有效的。然后我们会根据请求的 Tag 和 URL 来获取适配器
,并使用适配器来执行请求。
callAdapter
适配器的作用是将请求的参数适配成 OkHttp 能够识别的形式,并将 OkHttp 的响应适配成我们需要的形式。Retrofit 提供了一系列的适配器,包括 Call 适配器、RxJava 适配器、CompletableFuture 适配器等。
我们来看一下
方法的实现:
callAdapter
private CallAdapter<?, ?> callAdapter(Call<?> call, Object tag) {
Type responseType = call.request().method().equals("HEAD")
? Void.class
: getParameterUpperBound(0, (ParameterizedType) call.request().tag());
return callAdapter(tag, responseType);
}
在这个方法中,我们首先根据请求的方法来判断响应的类型,如果是 HEAD 方法,那么响应的类型就是 Void;否则我们会通过反射来获取请求的响应类型,并使用这个响应类型来获取适配器。
获取适配器的方法是
:
callAdapter
public <R, T> CallAdapter<R, T> callAdapter(Object tag, Type returnType) {
// ...
for (CallAdapter.Factory factory : adapterFactories) {
CallAdapter<?, ?> adapter = factory.get(returnType, annotations, this);
if (adapter != null) {
return (CallAdapter<R, T>) adapter;
}
}
// ...
}
在这个方法中,我们会遍历所有的适配器工厂,尝试获取适配器。在获取适配器时,我们会将请求的响应类型、注解和 Retrofit 实例作为参数传入。每个适配器工厂都会判断这些参数是否符合自己的适配条件,如果符合,就返回一个适配器实例,否则返回 null。在遍历完所有的适配器工厂之后,如果还没有获取到适配器,那么就会抛出一个异常。
获取到适配器之后,我们就可以使用适配器来执行请求了。在适配器中,我们会将请求参数转换成 OkHttp 的 Request 对象,并将 OkHttp 的 Response 对象转换成我们需要的响应类型。具体的实现可以参考 Retrofit 提供的
接口。
CallAdapter
对于
方法,我们可以先来看一下
enqueue
方法的实现:
enqueue
public <T> void enqueue(Call<T> call, Callback<T> callback) {
Utils.validateServiceInterface(call.request().tag(), call.request().url().toString());
callAdapter(call, call.request().tag()).adapt(call).enqueue(new CallbackRunnable<>(callback));
}
在这个方法中,我们首先进行接口校验,然后根据请求的 Tag 和 URL 来获取适配器,并使用适配器来执行请求。不同的是,在
方法中,我们将一个 Callback 对象作为参数传入适配器的
enqueue
方法中,以便在请求完成后回调通知我们。
enqueue
在适配器中,我们可以看到
方法的实现:
enqueue
public void enqueue(final Callback<T> callback) {
delegate.enqueue(new Callback<Response<T>>() {
@Override public void onResponse(Call<Response<T>> call, Response<Response<T>> response) {
Response<T> body;
try {
body = response.body();
} catch (Throwable t) {
if (response.code() == 204) {
body = null;
} else {
callback.onFailure(call, t);
return;
}
}
if (response.isSuccessful()) {
callback.onResponse(call, Response.success(body, response.raw()));
} else {
callback.onFailure(call, Response.error(response.errorBody(), response.raw()));
}
}
@Override public void onFailure(Call<Response<T>> call, Throwable t) {
callback.onFailure(call, t);
}
});
}
在这个方法中,我们会将传入的 Callback 对象转换成一个
对象,并使用这个对象来调用 OkHttp 的 enqueue 方法。在请求完成后,我们会将 OkHttp 的 Response 对象转换成 Retrofit 的 Response 对象,并根据响应码来判断请求的结果。如果响应码表示请求成功,那么我们就调用 Callback 对象的
Callback<Response<T>>
方法;否则就调用 Callback 对象的
onResponse
方法。
onFailure
响应处理
在 Retrofit 中,我们可以通过定义一个接口并使用注解来描述我们期望的请求格式和响应格式。例如,我们可以通过
注解来描述一个 GET 请求,使用
@GET
注解来描述请求参数,使用
@Query
注解来描述请求体,使用
@Body
注解来描述请求头等。
@Headers
在执行请求时,Retrofit 会根据这些注解来自动生成一个对应的请求对象,并将请求对象转换成 OkHttp 的 Request 对象。在接收响应时,Retrofit 会将 OkHttp 的 Response 对象转换成一个对应的响应对象,并将响应对象中的数据转换成我们需要的数据类型。这些转换工作是通过 Retrofit 的转换器来完成的,Retrofit 中默认提供了两个转换器:
和
GsonConverterFactory
。我们也可以自定义一个转换器来实现我们期望的数据转换。
JacksonConverterFactory
在 Retrofit 类的构造方法中,我们可以看到 Retrofit 默认使用了
方法来获取当前运行平台的默认转换器工厂,并将其添加到
Platform.get()
中。然后,我们可以使用
converterFactories
方法来添加自定义的转换器工厂。
addConverterFactory
public Retrofit(Builder builder) {
// ...
if (builder.converterFactories == null) {
converterFactories.add(Platform.get().defaultConverterFactory());
} else {
converterFactories.addAll(builder.converterFactories);
}
// ...
}
public interface Platform {
// ...
Converter.Factory defaultConverterFactory();
}
在
方法中,我们会调用适配器的 adapt 方法来执行请求,并将返回的 Call 对象转换成一个响应对象。在转换过程中,我们会根据响应类型来选择对应的转换器来进行转换。具体的转换实现可以参考 Retrofit 提供的
execute
接口和
Converter
接口。
Converter.Factory
public <T> T execute(Call<T> call) throws IOException {
// ...
Response<T> response = call.execute();
if (response.isSuccessful()) {
return response.body();
} else {
Converter<ResponseBody, ErrorResponse> converter = retrofit.responseBodyConverter(
ErrorResponse.class, new Annotation[0]);
throw new ApiException(converter.convert(response.errorBody()));
}
}
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
public <T> T adapt(Call<T> call) {
return (T) new OkHttpCall<>(requestFactory, callFactory, converter, call);
}
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
Objects.requireNonNull(type, "type == null");
Objects.requireNonNull(annotations, "annotations == null");
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
return (Converter<ResponseBody, T>) converter;
}
}
throw new IllegalArgumentException(
"Could not locate ResponseBody converter for " + type + " with annotations " + Arrays.toString(annotations));
}
以上是 Retrofit 中处理响应的核心代码。当我们执行一个请求时,Retrofit 会先将请求转换成 OkHttp 的 Request 对象并发送出去,然后等待响应返回。当响应返回时,Retrofit 会将响应转换成一个响应对象,并将响应对象中的数据转换成我们期望的数据类型。这个过程中,我们可以使用 Retrofit 提供的转换器来自定义数据的转换规则。
下面是一个示例,演示了如何使用 Retrofit 来发送一个 GET 请求并将响应中的 JSON 数据转换成一个 Java 对象:
public interface ApiService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService apiService = retrofit.create(ApiService.class);
Call<List<Repo>> call = apiService.listRepos("smallmarker");
List<Repo> repos = call.execute().body();
在上面的示例中,我们首先使用 Retrofit 构建器创建一个 Retrofit 实例,并指定了请求的基础 URL 和转换器工厂。然后,我们通过调用
方法来创建一个
create
的代理对象。最后,我们调用
ApiService
方法来发送一个 GET 请求。
listRepos
在上面的示例中,我们使用了 Retrofit 的
来将响应体中的 JSON 数据转换成 Java 对象。具体实现可以查看 Retrofit 提供的
GsonConverterFactory
类。
GsonConverterFactory
public final class GsonConverterFactory extends Converter.Factory {
private final Gson gson;
private GsonConverterFactory(Gson gson) {
this.gson = gson;
}
public static GsonConverterFactory create() {
return create(new Gson());
}
public static GsonConverterFactory create(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
return new GsonConverterFactory(gson);
}
@Override
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
@Override
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations,
Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
可以看到,
继承了 Retrofit 的
GsonConverterFactory
类,并重写了其中的
Converter.Factory
方法和
responseBodyConverter
方法。在
requestBodyConverter
方法中,我们将响应体中的 JSON 数据转换成 Java 对象,而在
responseBodyConverter
方法中,我们将 Java 对象转换成请求体中的 JSON 数据。
requestBodyConverter
除了
以外,Retrofit 还提供了其他的转换器,如
GsonConverterFactory
等,我们可以根据需要选择适合自己的转换器。
JacksonConverterFactory、MoshiConverterFactory
总的来说,Retrofit 中网络请求和响应处理的核心代码非常简洁明了。我们只需要通过定义接口来描述请求和响应,然后使用 Retrofit 的动态代理机制来将接口转换成一个实际的实现类,并通过 Retrofit 的配置来指定请求和响应的转换器即可。这种方式大大简化了网络请求的流程,使得我们可以更加专注于业务逻辑的处理。
以上就是Retrofit网络请求和响应处理源码分析的详细内容,更多关于Retrofit网络请求和响应处理源码分析的资料请关注九品源码其它相关文章!