Retrofit源码赏析三 —— ServiceMethod

·  阅读 568
Retrofit源码赏析三 —— ServiceMethod

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情

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<List>和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恢复挂起并返回数据,如果失败则恢复挂起抛出异常。

分类:
Android
标签:
分类:
Android
标签:
收藏成功!
已添加到「」, 点击更改