前情提要
上一篇博客把Retrofit的初始化大致了解了一下,Retrofit的初始化可以通过构造体也可以通过其内部类Builder进行创建。
链接:http://blog.csdn.net/wning1/article/details/78057571
本文接着上一篇向下分析源码:
还是粘贴一下Retrofit 官网上提供的一个简单的例子
Demo
interface:
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);
retrofit 网络请求,异步:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service=retrofit.create(GitHubService.class);
Call<List<Contributor>> repos = service.contributors("square", "retrofit");
repos.enqueue(new Callback<List<Contributor>>() {
@Override
public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
List<Contributor> contributors = response.body();
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
}
@Override
public void onFailure(Call<List<Contributor>> call, Throwable t) {}
});
代码分析
Retrofit初始化完毕,就该调用create()方法
create()
Retrofit初始化完成之后,就需要调用create()方法。看一下代码:
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) { //Retrofit初始化需要传递validataEagerly参数,如果该值为true,就是先去验证Github.class中定义的方法是否负责Retrofit的要求,不符合就抛出异常退出。默认情况validateEagerly 为false
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//... 省略代码
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
create() 方法是一个泛型方法,传入的是类型返回就是什么类型。在本例传入的是Github class 所以返回的就是Github 对象。对象的产生是通过Poxy代理出来的。Github对象并不会立即被创建出来,触发执行该段代码是在执行完demo中的service.contributors(“square”, “retrofit”); 这句代码。运行到loadServiceMethod并返回ServiceMethod 对象,本文将会loadServiceMethod相关联的代码,至于17,18行,OkhttpCall 下一篇blog在继续。
loadServiceMethod
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
该方法返回ServiceMethod对象。ServiceMethod 通过集合serviceMethodCache 得到,serviceMethodCache键:Method对象,值:ServiceMethod对象。如果找到值就返回,没有则创建ServiceMethod,并添加到集合中。
ServiceMethod 类主要的作用:解析Method方法中的注解,并存储到ServiceMethod。
ServiceMethod是通过自身内部类Builder进行创建的。先看一下ServiceMethod构造体:
ServiceMethod
ServiceMethod(Builder<R, T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl(); //url Retrofit.Build baseUrl方法得到
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod; //网络请求方式:get or post
this.relativeUrl = builder.relativeUrl; //相对路径 我会在Retrofit中设置baseurl
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;//一维数组
}
上面ServiceMethod的属性值通过内部类Builder赋值的。看一下Builder是怎么解析Method的。拿本文Demo来说,就是解析的如下方法:
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);
ServiceMethod.Builder 构造体 :
ServiceMethod.Builder 构造体
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method; //Method对象
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
ServiceMethod.Buildler 构造体方法需要传递Retrofit 和 Method 参数,Builder解析的也正是Method对象,这一部分涉及到的Method的api方法较多,要想理解代码还真需要查看一下java的api.
- getAnnotations () //一维数组 Annotation[] : @GET(...)
- getGenericParameterTypes() //一维数组 Type[]
- getParameterAnnotations()//二维数组 Annotation[][]
- getGenericReturnType 获取返回数据类型 // Type
- getRawType 获取<> 前面实际类型 例如Call<List<Contributor>> 值为Call
在本Demo中getAnnotations () @GET(“/repos/{owner}/{repo}/contributors”)
getGenericParameterTypes 获取是一个数组,里面存储着两个值:分别为onwer 和 repo 的参数类型String.class 。
getParameterAnnotations 获取的则是方法传递参数的注解数组,返回值是一个二维数组,为什么是一个二维数组呢?原因:每一个形参可有多个注解。如果我把本Demo中method改成如下:
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(@Part() @Path("owner") String owner, @Part() @Path("repo") String repo);
那么二维数组存储值分别为:
【0】【0】 : @part 【0】【1】 : @part 【1】【0】: @part 【1】【1】 : @path
ServiceMethod.Builder 生成callAdapter :
着重看一下Builder的build()方法,对Method的解析几乎都在这个地方,一步一步的解析build()里面的代码:
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
return new ServiceMethod<>(this);
}
首先build 调用 createCallAdapter 方法。
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
...//省略部分代码
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
首先获取到返回数据类型returnType,如果返回数据类型符合数据类型符合要求,则调用Retrofit的createCallAdapter中并返回CallAdapter。最终调用代码如下:
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
}
skipPast传入值为null,从上一篇文章我们知道 adapterFactoryies 目前就存储着一个值ExecutorCallAdapterFactory。
ExecutorCallAdapterFactory代码:
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
在本Demo中getRawType返回值类型为为Call.class , getCallResponseType 为 List,ok ! 目前对ServiceMethod 中如下变量分别赋值:
- callAdapter //ExecutorCallAdapterFactory. CallAdapter
- responseType // List
ServiceMethod.Builder 获取转换工厂 :
public ServiceMethod build() {
responseConverter = createResponseConverter();
}
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
最终调用Retrofit中nextResponseBodyConverter:
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(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) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
}
skipPast 为null ,method.getAnnotions 值为@GET(“/repos/{owner}/{repo}/contributors”)
converterFactories 中共存储两个值:BuiltInConverters 和 GsonConverterFactory ,for循环遍历BuiltInConverters 的到的converter 为null ,GsonConverterFactory 得到的converters不为null.则ServiceMethod 中如下变量分别赋值:
- responseConverter //GsonConverterFacory
ServiceMethod.Builder : 解析方法注解
public ServiceMethod build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//...省略部分代码 >主要判断hasBody为false情况下也就是请求方式为GET 不能使用 Multipart(文件上传) FormUrlEncoded(表单) 注解
}
parseMethodAnnotation:
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
}
//... 省略部分代码
}
parseHttpMethodAndPath:
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value.isEmpty()) {
return;
}
// Get the relative URL path and existing query string, if present.
int question = value.indexOf('?');
if (question != -1 && question < value.length() - 1) {
// Ensure the query string does not have any named parameters.
String queryParams = value.substring(question + 1);
Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
if (queryParamMatcher.find()) {
throw methodError("URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
本Demo 传递的是@Get,执行完parseHttpMethodAndPath方法对ServiceMethod 中如下变量分别赋值:
- httpMethod //String:GET
- hasBody // false get形式没有请求体,Post 则有请求体
- relativeUrl // /repos/{owner}/{repo}/contributors
- relativeUrlParamNames // Set 集合存储着{ }中的字符串,分别为owner ,repo
其中parsePathParameter 则是通过正则表达式进行选取的,可自行查看源码。
ServiceMethod.Builder : 解析传递参数注解
public ServiceMethod build() {
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);
}
}
在本Demo中parameterCount 为2, parameterAnnotations 存储 @Path , 继续向下看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;
}
result = annotationAction;
}
return result;
}
parseParameter方法中又调用了 parseParameterAnnotation 方法,该方法的代码实在是好长呀,只摘抄涉及到本Demo的代码啦!
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Url) {
gotUrl = true;
//...省略部分代码
} 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());
} else if (annotation instanceof Query) {
gotQuery = true;
//...省略部分代码
} else if (annotation instanceof QueryName) {
gotQuery = true;
//...省略部分代码
}
return null; // Not a Retrofit annotation.
}
在本Demo中annotation 的为@Path,所以直接看该部分代码,首先gotPath = true , 可以看到如果是其他类型也会有相应的boolean值赋值。path.value 为owner 或者repo,然后又调用了retrofit.stringConverter
public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
for (int i = 0, count = converterFactories.size(); i < count; i++) {
Converter<?, String> converter =
converterFactories.get(i).stringConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<T, String>) converter;
}
}
// Nothing matched. Resort to default converter which just calls toString().
//noinspection unchecked
return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE;
}
在本Demo中converterFactories存储这BuiltInConverters 和 GsonConverterFactory 这两个类型对象,但是这两个对象都没有复写stringConverter 方法,所以最终返回BuiltInConverters.ToStringConverter.INSTANCE、
最后看一下parseParameterAnnotation 中 return new ParameterHandler.Path<>(name, converter, path.encoded());
static final class Path<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Path(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) {
throw new IllegalArgumentException(
"Path parameter \"" + name + "\" value must not be null.");
}
builder.addPathParam(name, valueConverter.convert(value), encoded);
}
}
Path 是ParameterHandler的内部类,复写的apply方法调用了RequestBuilder 的addPathParam
void addPathParam(String name, String value, boolean encoded) {
if (relativeUrl == null) {
// The relative URL is cleared when the first query parameter is set.
throw new AssertionError();
}
relativeUrl = relativeUrl.replace("{" + name + "}", canonicalizeForPath(value, encoded));
}
将relativeurl { }中的内容替换成为parameterAnnocationd的value值。如本Demo中 /repos/{owner}/{repo}/contributors 转换之后为:/repos/owner/repo/contributors。
总结
至此Mehtod的注解则全部解析完毕。那么总结ServiceMethod :该类的作用就是解析Method数据(包括注解)存储到ServiceMethod中,便于接下来OkHttpCall 调用。