文章目录
在使用Retrofit时会定义一个接口类,在访问网络时会调用该接口中的方法访问网络。这一过程时通过动态代理实现的,在我们使用Retrofit实例的getApi()方法时,实际会使用Proxy.newProxyInstance()来创建一个接口类的动态代理对象。使用Paging3时接口定义为:
//interface HomeHttpApiReplace
interface HomeHttpApiReplace {
@GET("data/page/v2/{id}")
suspend fun getHomePageConfig(
@Path("id") pageId: Int, @Query("uid") uid: Long?,
@Query("categoryList") categoryList: String
): HomePageDataConfig
}
//class HomeDataPagingSource
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, BaseItemData> {
val homePageConfig = api.getHomePageConfig(tabId, getUid(),
StringUtils.join(RecommendCore.instance.queryCacheCategory(), ","))
}
Api接口类的动态代理过程
根据动态代理原理,调用getHomePageConfig()方法就会调用InvocationHandler类的invoke()方法:
//class Retrofit.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);
}
});
}
这里,platform为Android,method 即是public abstract java.lang.Object com.yy.onepiece.home.view.LivingHomeViewReplace.HomeHttpApiReplace.getHomePageConfig(int,java.lang.Long,java.lang.String,kotlin.coroutines.Continuation),可以看到其函数参数中多了一个类型为Continuation的参数。
//class Retrofit.java
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;
}
第一次调用该方法是不存在缓存的,因此会解析该方法的注解。
解析Api接口中方法注解的过程
//abstract class ServiceMethod
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);
}
首先,采用Builder设计模式将method包含的信息存储在创建的RequestFactory对象内,看一下这一过程:
//class RequestFactory.java
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
//class RequestFactory.Builder
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
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);
}
这里分两步解析注解,第一步是解析方法注解,即@GET等,第二步是解析参数注解,即@Path等。
1. 解析方法注解的过程
解析方法注解的过程为:
//class RequestFactory.java
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;
}
}
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
//省略代码安全检查
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value.isEmpty()) {
return;
}
//省略代码安全检查
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
static Set<String> parsePathParameters(String path) {
Matcher m = PARAM_URL_REGEX.matcher(path);
Set<String> patterns = new LinkedHashSet<>();
while (m.find()) {
patterns.add(m.group(1));
}
return patterns;
}
分别针对DELETE、GET等等类型的注解进行解析,解析结果保存在httpMethod字段,注解相应的value保存在relativeUrl字段,对value进一步解析程Set形式保存在relativeUrlParamNames字段。
2. 解析参数注解过程
解析参数注解过程为:
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(
method, p, "Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
}
if (result == null) {
if (allowContinuation) {
try {
if (Utils.getRawType(parameterType) == Continuation.class) {
isKotlinSuspendFunction = true;
return null;
}
} catch (NoClassDefFoundError ignored) {
}
}
throw parameterError(method, p, "No Retrofit annotation found.");
}
return result;
}
parseParameter()函数目的是解析每一个函数参数的,每个参数可能包含多个注解,根据每个参数的注解个数,进一步调用parseParameterAnnotation()方法解析,解析结果是一个ParameterHandler对象result,根据解析的注解对象如@Path、@Query等会被解析生成ParameterHandler的子类对象如ParameterHandler.Path、ParameterHandler.Query等。如果有一个参数没有注解或者注解不在给定类型内,则result = null。根据开头Api定义的方法具有suspend标识,因此该方法会在参数中包含一个Continuation类型的参数,因此result == null会为真,因此在allowContinuation为true情况下isKotlinSuspendFunction被置为true。
对Call的适配过程
下面回到ServiceMethod的parseAnnotations()函数,会调用HttpServiceMethod.parseAnnotations()。
/**
* 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) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
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);
}
}
这段代码虽然很长,但是逻辑却十分清晰。首先根据isKotlinSuspendFunction字段来决定Adapter的类型,这里该值为true,记录在adapterType中,是一个ParameterizedTypeImpl实例,并在工厂callAdapterFactories中去创建一个CallAdapter对象。其次根据responseType来在工厂converterFactories中创建一个Converter对象。最后根据isKotlinSuspendFunction来判断返回一个普通形式的CallAdapted对象还是一个支持协程的挂起形式的适配对象,挂起形式的适配对象有两个,其不同之处在于返回值,通过continuationWantsResponse来判断,其中SuspendForBody的返回结果是Response.body对象,SuspendForResponse的返回结果是Response对象。
下面回到InvocationHandler的invoke()方法中,会进一步调用ServiceMethod的invoke()虚方法,ServiceMethod只有一个子类HttpServiceMeth,SuspendForBody又是HttpServiceMeth的子类。
//class HttpServiceMeth.java
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
//class SuspendForBody
protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call);
//noinspection unchecked Checked by reflection inside RequestFactory.
Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
// Calls to OkHttp Call.enqueue() like those inside await and awaitNullable can sometimes
// invoke the supplied callback with an exception before the invoking stack frame can return.
// Coroutines will intercept the subsequent invocation of the Continuation and throw the
// exception synchronously. A Java Proxy cannot throw checked exceptions without them being
// declared on the interface method. To avoid the synchronous checked exception being wrapped
// in an UndeclaredThrowableException, it is intercepted and supplied to a helper which will
// force suspension to occur so that it can be instead delivered to the continuation to
// bypass this restriction.
try {
return isNullable
? KotlinExtensions.awaitNullable(call, continuation)
: KotlinExtensions.await(call, continuation);
} catch (Exception e) {
return KotlinExtensions.suspendAndThrow(e, continuation);
}
}
这里的callAdapter即是前文HttpServiceMethod.parseAnnotations()中构造SuspendForBody实例时传入的,是一个DefaultCallAdapterFactory.CallAdapter实例,是通过createCallAdapter()方法调用工厂类的get()方法获取是初始化的匿名对象。这里调用callAdapter.adapt(call)来对call对象进行适配。
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);
}
};
}
这里的executor = null,因此会用call做为参数构造一个ExecutorCallbackCall对象,因此调用callAdapter.adapt(call)返回一个ExecutorCallbackCall对象。
回到SuspendForBody类的adapt()方法,通过Continuation continuation = (Continuation<ResponseT>) args[args.length - 1]这句代码可以获取Api接口中定义的saspend方法传入的Continuation类型参数,接下来因为isNullable == false,因此会调用KotlinExtensions.await(call, continuation),这是一个Java方法,有一个类型为ExecutorCallbackCall参数call和一个类型为Continuation的continuation,这里调用的是一个suspend Kotlin方法 Call.await(),该Kotlin编译成Java方法时会增加这两个参数。
suspend fun <T : Any> Call<T>.await(): T {
return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
cancel()
}
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
val body = response.body()
if (body == null) {
val invocation = call.request().tag(Invocation::class.java)!!
val method = invocation.method()
val e = KotlinNullPointerException("Response from " +
method.declaringClass.name +
'.' +
method.name +
" was null but response body type was declared as non-null")
continuation.resumeWithException(e)
} else {
continuation.resume(body)
}
} else {
continuation.resumeWithException(HttpException(response))
}
}
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
先是挂起了当前协程,记录当前挂起点为continuation,然后调用ExecutorCallbackCall对象的enqueue()方法:
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
this.delegate.enqueue(new Callback<T>() {
public void onResponse(Call<T> call, Response<T> response) {
ExecutorCallbackCall.this.callbackExecutor.execute(() -> {
if (ExecutorCallbackCall.this.delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
public void onFailure(Call<T> call, Throwable t) {
ExecutorCallbackCall.this.callbackExecutor.execute(() -> {
callback.onFailure(ExecutorCallbackCall.this, t);
});
}
});
}
public boolean isExecuted() {
return this.delegate.isExecuted();
}
public Response<T> execute() throws IOException {
return this.delegate.execute();
}
public void cancel() {
this.delegate.cancel();
}
public boolean isCanceled() {
return this.delegate.isCanceled();
}
public Call<T> clone() {
return new DefaultCallAdapterFactory.ExecutorCallbackCall(this.callbackExecutor, this.delegate.clone());
}
public Request request() {
return this.delegate.request();
}
public Timeout timeout() {
return this.delegate.timeout();
}
}
这里用了代理模式,ExecutorCallbackCall是一个代理类,使用类型为Call的delegate对象来处理访问网络工作。外部调用ExecutorCallbackCall类的enqueue()方法实际是交给delegate进一步处理,网络处理结果会返回给类型为Callback的callback处理,也就是在前一段代码中进行处理,若回调onResponse()方法且结果无异常,则通过 continuation.resume(body)回到挂起点恢复执行,若回调onFailure()方法,则通过continuation.resumeWithException(t)回到挂起点恢复执行并返回异常。
Converter原理
Converter的作用是在网络访问前后对网络访问过程中的某些数据进行自定义的转换,比如Retrofit库中默认的RequestBodyConverter、GsonResponseBodyConverter等。Converter是一个接口,看一下其定义:
//Converter.java
public interface Converter<F, T> {
@Nullable
T convert(F value) throws IOException;
/** Creates {@link Converter} instances based on a type and target usage. */
abstract class Factory {
/**
* Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for
* response types such as {@code SimpleResponse} from a {@code Call<SimpleResponse>}
* declaration.
*/
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
/**
* Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap} values.
*/
public @Nullable Converter<?, RequestBody> requestBodyConverter(
Type type,
Annotation[] parameterAnnotations,
Annotation[] methodAnnotations,
Retrofit retrofit) {
return null;
}
/**
* Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Field @Field}, {@link FieldMap @FieldMap} values, {@link Header @Header},
* {@link HeaderMap @HeaderMap}, {@link Path @Path}, {@link Query @Query}, and {@link
* QueryMap @QueryMap} values.
*/
public @Nullable Converter<?, String> stringConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
/**
* Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
* example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
/**
* Extract the raw class type from {@code type}. For example, the type representing {@code
* List<? extends Runnable>} returns {@code List.class}.
*/
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
Converter接口中只定义了一个方法convert(),将类型F的value值转换为类型为T的值,另外还定义了一个Factory虚内部类,Factory工厂类是用于生产Converter对象的,其中定义了四个方法,通过注释可以很清楚地知道这四个方法的作用。responseBodyConverter()方法的作用是产生一个将网络返回body转换成Type类型的Converter对象;requestBodyConverter()方法的作用是产生一个将Type转换为请求body的Converter对象;getParameterUpperBound()方法的作用是提取类型为ParameterizedType的泛型列表中第index个泛型的上界类型;getRawType()方法的作用是获取type的原始类型。在Converter接口头的注释说明所有的Converter对象是通过Retrofit.Builder#addConverterFactory(Factory)添加的,下面来看一下Retrofit添加Converter的过程,定义在Retrofit类中的内部类Builder中:
//class Retrofit.Builde
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
return this;
}
当使用者调用addConverterFactory()方法时,会将传入的factory存放在内部的converterFactories列表中,并返回该Builder。创建一个Retrofit对象均是调用其内部类Builder的build()方法来实现的:
class Retrofit.Builde
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();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
//必定存在一个BuiltInConverters对象,平台默认的ConVerterFactory可能不存在
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
该段代码主要做两件事情:
- 将原来的callAdapterFactories列表和平台提供的默认CallAdapterFactorie列表组合成一个列表传给Retrofit的构造函数;
- 将BuiltInConverters和原来的callAdapterFactories和平台提供的默认ConverterFactory列表组合成一个列表穿个Retrofit的构造函数,平台提供的默认ConverterFactory列表只有当hasJava8Types为true时才会存在。
上面介绍了ConverterFacrory的添加过程,下面我们看看两种常用的Converter的使用过程,这两种Converter对应的工厂类型分别是:RequestConverterFactory和ResponseConverterFactory。
RequestBodyCoverter转换过程
RequestConverterFactory的添加是在api方法解析的时候,其调用时许如下图所示,其解析过程在解析Api接口中方法注解的过程一节已经分析过了,下面主要关注RequestConverterFactory的添加。
在RequestFactory的parseParameterAnnotation()方法中可以看到解析Api方法中的每一个参数类型的过程,但是只有@Part、@PartMap、@Body三个注解所注解的参数才会为期添加一个RequestConverterFactory,下面看看有关@Body的代码:
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if() {
//...
} else if (annotation instanceof Body) {
validateResolvableType(p, type);
if (isFormEncoded || isMultipart) {
throw parameterError(
method, p, "@Body parameters cannot be used with form or multi-part encoding.");
}
if (gotBody) {
throw parameterError(method, p, "Multiple @Body method annotations found.");
}
Converter<?, RequestBody> converter;
try {
converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations);
} catch (RuntimeException e) {
// Wide exception range because factories are user code.
throw parameterError(method, e, p, "Unable to create @Body converter for %s", type);
}
gotBody = true;
return new ParameterHandler.Body<>(method, p, converter);
}
}
可以看到是通过调用Retrofit的requestBodyConverter()方法来获得一个将Type转换为RequestBody的转换器工厂实例,在Retrofit内部又会调用nextRequestBodyConverter()方法进一步处理:
public <T> Converter<T, RequestBody> nextRequestBodyConverter(
@Nullable Converter.Factory skipPast,
Type type,
Annotation[] parameterAnnotations,
Annotation[] methodAnnotations) {
Objects.requireNonNull(type, "type == null");
Objects.requireNonNull(parameterAnnotations, "parameterAnnotations == null");
Objects.requireNonNull(methodAnnotations, "methodAnnotations == null");
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter.Factory factory = converterFactories.get(i);
Converter<?, RequestBody> converter =
factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<T, RequestBody>) converter;
}
}
throw new IllegalArgumentException(builder.toString());
}
这里就是遍历Retrofit中的converterFactories列表来查询是否有相应的转换器工厂实例,converterFactories是上一节讨论的外部添加和内部添加的所有转换器工厂实例的缓存列表。然后就可以调用工厂类的requestBodyConverter()方法获取一个将Type转换成RequestBody的Converter来实现转换功能。最后还要看一下该RequestBodyConverter的convert()方法是在哪儿被调用的。我们知道每个请求参数被解析成对象ParameterHandler,相应的转换器保存在类型为Converter<T, RequestBody>的成员变量
converter中,看一下其中一个子类Body的定义:
static final class Body<T> extends ParameterHandler<T> {
private final Method method;
private final int p;
private final Converter<T, RequestBody> converter;
@Override
void apply(RequestBuilder builder, @Nullable T value) {
if (value == null) {
throw Utils.parameterError(method, p, "Body parameter value must not be null.");
}
RequestBody body;
try {
body = converter.convert(value);
} catch (IOException e) {
throw Utils.parameterError(method, e, p, "Unable to convert " + value + " to RequestBody");
}
builder.setBody(body);
}
}
Body中重写了apply()方法来实现将@Body注解的参数转换成RequestBody对象。看一下Body中的apply()方法被调用的地方:
//RequestFactory.java
okhttp3.Request create(Object[] args) throws IOException {
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args.length;
RequestBuilder requestBuilder =
new RequestBuilder(
httpMethod,
baseUrl,
relativeUrl,
headers,
contentType,
hasBody,
isFormEncoded,
isMultipart);
if (isKotlinSuspendFunction) {
// The Continuation is the last parameter and the handlers array contains null at that index.
argumentCount--;
}
List<Object> argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}
可以看到在RequestFactory类中的create()方法中会遍历所有ParameterHandler的子类对象,并调用其apply()方法。RequestFactory类中的create()方法又是在OkHttpCall中创建一个Call时被调用的:
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
从这里可知:RequestFactory是用来创建一个新的Request的,而每次发起网络请求是通过Call对象,Call对象又依赖与Request对象,因此网络请求必须新建一个Request对象,每个Request对象的所有参数的Converter就是在这个时候执行转换操作的。
ResponseBodyCoverter转换过程
我们知道Retrofit中还有一个responseBodyConverter()方法用于获取ResponseBodyCoverter。回到HttpServiceMethod的parseAnnotations()方法,发现在构造CallAdapted对象、SuspendForResponse对象和SuspendForBody对象时都会传一个RequestFactory类型的参数,然后保存在其父类HttpServiceMethod的成员变量requestFactory中。我们又知道解析完一个HttpServiceMethod对象后会调用其invok()方法发起请求:
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
可以看到最终这个responseConverter传到了OkHttpCall对象中去了,下面关注OkHttpCall对象中的responseConverter在什么时候被使用:
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;
}
}
可以看到是在请求返回后解析返回结果时将ResponseBody转换为相应的Type的。