在第一章节讲到了ServiceMethod的toRequest()方法,下面就从toRequest()方法方法开始分析ServiceMethod,toRequest()的源码如下:
Request toRequest(Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);//这里是参数参数配置的核心
}
return requestBuilder.build();
}
先来看一下handlers(也就是parameterHandlers)这个属性的功能。parameterHandlers的初始化在ServiceMethod的内部类Builder的build()方法中初始化。build()方法如下:
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
int parameterCount = parameterAnnotationsArray.length;//方法的参数的所有注解
parameterHandlers = new ParameterHandler<?>[parameterCount];//初始化
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {//参数类型检查
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
//保存了参数类型和参数的注解
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
这里先补充一点反射的知识。
Annotation[] annotations = method.getAnnotations();//获取方法的所有注解
Annotation[][] annos = method.getParameterAnnotations();//获取方法的参数的所有注解。
Type[] t = m.getGenericParameterTypes();//返回方法的参数列表
Utils.hasUnresolvableType()这个方法的源码如下:
static boolean hasUnresolvableType(Type type) {
if (type instanceof Class<?>) {
return false;
}
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
for (Type typeArgument : parameterizedType.getActualTypeArguments()) {
if (hasUnresolvableType(typeArgument)) {
return true;
}
}
return false;
}
if (type instanceof GenericArrayType) {
return hasUnresolvableType(((GenericArrayType) type).getGenericComponentType());
}
if (type instanceof TypeVariable) {
return true;
}
if (type instanceof WildcardType) {
return true;
}
String className = type == null ? "null" : type.getClass().getName();
throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
+ "GenericArrayType, but <" + type + "> is of type " + className);
}
hasUnresolvableType()其实就是做了参数的类型检查。具体各个类型代表的含义,可以百度反射相关知识。
parseParameter()方法源码如下:
private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
if (result == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
return result;
}
接着看parseParameterAnnotation()的源码:
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
//如果注解是Url
if (annotation instanceof Url) {
if (gotUrl) {
throw parameterError(p, "Multiple @Url method annotations found.");
}
if (gotPath) {
throw parameterError(p, "@Path parameters may not be used with @Url.");
}
if (gotQuery) {
throw parameterError(p, "A @Url parameter must not come after a @Query");
}
if (relativeUrl != null) {
throw parameterError(p, "@Url cannot be used with @%s URL", httpMethod);
}
gotUrl = true;
if (type == HttpUrl.class
|| type == String.class
|| type == URI.class
|| (type instanceof Class && "android.net.Uri".equals(((Class<?>) type).getName()))) {
return new ParameterHandler.RelativeUrl();//如果没有异常,返回Url对应的ParameterHandler。
} else {
throw parameterError(p,
"@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
}
} else if (annotation instanceof Path) {
if (gotQuery) {
throw parameterError(p, "A @Path parameter must not come after a @Query.");
}
if (gotUrl) {
throw parameterError(p, "@Path parameters may not be used with @Url.");
}
if (relativeUrl == null) {
throw parameterError(p, "@Path can only be used with relative url on @%s", httpMethod);
}
gotPath = true;
Path path = (Path) annotation;
String name = path.value();
validatePathName(p, name);
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Path<>(name, converter, path.encoded());
}
……
}
RelativeUrl类的定义如下(其他的注解定义和使用方式都差不多,就不一一说明):
static final class RelativeUrl extends ParameterHandler<Object> {
@Override void apply(RequestBuilder builder, Object value) {
builder.setRelativeUrl(value);
}
}
RequestBuilder的setRelativeUrl()方法定义如下:
void setRelativeUrl(Object relativeUrl) {
//url不能为空
if (relativeUrl == null) throw new NullPointerException("@Url parameter is null.");
this.relativeUrl = relativeUrl.toString();
}
关于parameterHandlers就介绍到这里,总结起来就是parameterHandlers里面存放的是类似于RelativeUrl这样的类,专门用于处理各种注解。ServiceMethod的toRequest()方法,都会调用parameterHandlers里面的ParameterHandler的apply()方法。调用完之后,所有的参数都填入到RequestBuilder中去了。到此,Retrofit就完成了数据的收集功能。
网友评论