ServiceMethod
前面提到loadServiceMethod执行的时候会调用ServiceMethod.parseAnnotations()方法将method转化为ServiceMethod实例。
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = ServiceMethod.parseAnnotations(this, method);
}
ServiceMethod是一个抽象类,存储了我们网络请求的基本信息,他的parseAnnotations()方法如下
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()方法获取RequestFactory对象,它主要是解析我们定义在方法上面的注解。
- 然后判断方法的返回值是否合法:返回值不能包含泛型(如T)或者通配符(如? extends Number),并且返回值不能为void。
- 最后调用HttpServiceMethod.parseAnnotations()方法获取ServiceMethod对象。
HttpServiceMethod
HttpServiceMethod是ServiceMethod的子类
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {
//获取返回类型
Type adapterType;
//获取CallAdapter
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);
//获取Converter
Converter<ResponseBody, ResponseT> responseConverter =createResponseConverter(retrofit, method, responseType);
//创建返回值
return HttpServiceMethod;
}
获取返回类型
首先通过判断当前函数是不是挂起函数,然后初始化不同的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;
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
这里为什么需要区分函数是不是挂起函数呢,我们需要一个例子看一下:
suspend fun testSuspend(param:String):List<String>
suspend fun testResponse(param:String):Response<String>
fun testCommon(param:String):List<String>
我们先准备3个函数,前两个用suspend修饰,然后反编译为java代码
Object testSuspend(@NotNull String var1, @NotNull Continuation var2);
List testCommon(@NotNull String var1);
Object testResponse(@NotNull String var1, @NotNull Continuation var2);
可以看出,挂起函数转化为java代码之后会增加一个Continuation类型的参数,而且返回值会变为Object,这种情况下如果我们继续使用getGenericReturnType()获取返回值的话,就不能获取到真正的返回值,而真正的返回值可以通过Continuation参数获取,获取出来之后,如果返回值是 Response就还需要进一步获取真实类型T。最后对于挂起函数的返回值再用Call包装一下变为Call和Call。
获取CallAdapter
callAdapter最后是调用retrofit的nextCallAdapter()方法获取的。
public CallAdapter<?, ?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
//......省略异常日志
throw new IllegalArgumentException(builder.toString());
}
通过skipPast,returnType,annotations从创建Retrofit对象时候初始化的callAdapterFactories中筛选出我们需要的callAdapterFactory,然后调用它的get()方法获取CallAdapter。
获取ResponseConverter
responseConverter获取方式与callAdapter类似,也是在Retrofit类中获取的。
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast, Type type, Annotation[] annotations) {
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) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
//......省略异常日志
throw new IllegalArgumentException(builder.toString());
}
获取完converterFactory之后,由converterFactory创建Converter。
创建HttpServiceMethod对象
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>( requestFactory, callFactory,responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>( requestFactory, callFactory,responseConverter,(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,continuationBodyNullable);
}
最后根据isKotlinSuspendFunction和continuationWantsResponse创建不同的返回值,CallAdapted,SuspendForResponse,SuspendForBody三个类都是HttpServiceMethod的子类。
HttpServiceMethod还有一个重要的invoke()方法。它将传入的参数args配合requestFactory等其他参数一起构造了Call对象。
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
invoke()方法的调用是在前面的动态代理的代理类中。
//Retrofit.create()中,省略部分代码
new InvocationHandler() {
Object invoke(Object proxy, Method method, @Nullable Object[] args){
return loadServiceMethod(method).invoke(args)
}
});
invoke()方法创建了Call对象之后会调用抽象方法adapt(),adapt()的具体的逻辑由下面三个不同类型的HttpServiceMethod实现。
CallAdapted
如果没有使用Kotlin的协程,最后创建的是CallAdapted对象。
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
//.......省略构造函数
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
Retrofit为我们提供了一个默认的CallAdapter,他是由DefaultCallAdapterFactory创建,调用了callAdapter.adapt(call)之后,会将call包装成ExecutorCallbackCall对象,后续调用execute()方法执行请求。
需要注意的是只有形如Call或者Call<? extends Foo>的返回类型才会创建CallAdapter,对于其他类型比如Observable,需要我们自己提供CallAdapterFactory创建CallAdapter。如果没有提供则会创建CallAdapter失败,然后抛出异常。
SuspendForResponse
对于Kotlin的挂起函数,如果返回类型是Response类型,就会创建SuspendForResponse对象。
static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
//.......省略构造函数
protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call);
Continuation<Response<ResponseT>> continuation = (Continuation<Response<ResponseT>>) args[args.length - 1];
try {
return KotlinExtensions.awaitResponse(call, continuation);
} catch (Exception e) {
return KotlinExtensions.suspendAndThrow(e, continuation);
}
}
}
SuspendForBody
如果挂起函数返回类型不是Response类型,就会创建SuspendForBody对象。
static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
private final boolean isNullable;
//.......省略构造函数
protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call);
Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
try {
return isNullable? KotlinExtensions.awaitNullable(call, continuation) : KotlinExtensions.await(call,continuation);
} catch (Exception e) {
return KotlinExtensions.suspendAndThrow(e, continuation);
}
}
}
SuspendForResponse和SuspendForBody都是对Kotlin协程的支持,基本逻辑也是一致的,首先通过callAdapter.adapt(call)包装Call,然后调用KotlinExtensions中的方法并返回结果,由于java调用kotlin的suspend方法需要传入Continuation对象,所以会先从参数中获取出来。
@JvmName("awaitNullable")
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) {
continuation.resume(response.body())
} else {
continuation.resumeWithException(HttpException(response))
}
}
override fun onFailure(call: Call<T?>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
awaitResponse()和await()基本一致,这里以await()为例,通过suspendCancellableCoroutine,我们可以将回调转化为挂起协程。与之相似还有suspendCoroutine,不同的是suspendCancellableCoroutine获取到的协程是一个CancellableContinuation对象,它支持取消,在Retrofit中我们需要再协程取消的时候取消okhttp的请求,即在invokeOnCancellation 中调用cancel()方法
enqueue方法执行的是OkHttpCall的enqueue,最后会通过OkHttp发起网络请求。成功之后通过resume恢复挂起并返回数据,如果失败则恢复挂起抛出异常。