预习
- 动态代理
- 反射
本文主要对retrofit的源码进行学习,了解,学习其设计模式,与实现方式。
retrofit 的基本用法:
- Retrofit turns your HTTP API into a Java interface.
(将HTTP API转换为Java接口。)
public interface GitHubService {
@GET("users/{user}/repos")
Call> listRepos(@Path("user") String user);
}
复制代码
- The Retrofit class generates an implementation of the GitHubService interface.
(Retrofit类生成GitHubService接口的实现。)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
复制代码
- Each Call from the created GitHubService can make a synchronous or asynchronous HTTP request to the remote webserver.
(创建的GitHubService的每个调用都可以向远程web服务器发出同步或异步的HTTP请求。)
Call> repos = service.listRepos("octocat");
复制代码
A : service接口的构建
- 首先创建一个service的接口类。
- 指定请求方式 常见的有GET,POST,PUT,DELETE...,注意大小写。
- 配置请求地址,注意path的配置规则(见retrofit 使用教程的7.2)
BaseUrl | 和URL有关的注解中提供的值 | 最后结果 |
---|---|---|
http://localhost:4567/path/to/other/ | /post | http://localhost:4567/post |
http://localhost:4567/path/to/other/ | post | http://localhost:4567/path/to/other/post |
http://localhost:4567/path/to/other/ | github.com/ikidou | github.com/ikidou |
- 如果你在注解中提供的url是完整的url,则url将作为请求的url。
- 如果你在注解中提供的url是不完整的url,且不以 / 开头,则请求的url为baseUrl+注解中提供的值
- 如果你在注解中提供的url是不完整的url,且以 / 开头,则请求的url为baseUrl的主机部分+注解中提供的值
- 指定请求的回调对象,默认返回retrofit的Call
对象,这里我们可以
- 通过实现retrofit的CallAdapter
接口,来自定义我们的返回对象。 - 再继承CallAdapter.Factory生成我们自己的Factory,在get()方法返回我们自定义的CallAdapter。
- 最后调用Retrofit.Builder的addCallAdapterFactory(Factory)
- 指定请求结束后我们要接收的类型,如:okHttp返回默认的是ResponseBody,通过Retrofit的Converter可以转换为我们需要的 string 或 反序列化为java Bean对象等。
- 定义一个MyConvert类实现retrofit的Converter接口。
- 定义一个MyConvertFactory继承retrofit的Converter.Factory,实现responseBodyConverter()返回我们自定义的MyConvert类。
- 使用Retrofit.Builder.addConverterFactory(new MyConvertFactory())添加我们自定义的Factory.
- 定义我们请求的方法名字。
- 请求参数的注解 见(见retrofit 使用教程的第三类:参数类)
- 请求参数的名字
- 参数类型
- 参数名称
B : retrofit的构建,源码分析
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
复制代码
我们可以看到retrofit的构建使用了builder模式。
1. 看一下Retrofit.Builder类:
/**
* Build a new {@link Retrofit}.
*
* Calling {@link #baseUrl} is required before calling {@link #build()}. All other methods
* are optional.
*/
public static final class Builder {
private final Platform platform;
private @Nullable okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private final List converterFactories = new ArrayList<>();
private final List adapterFactories = new ArrayList<>();
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
...
}
复制代码
从源码可以看到:
- 从注释看到baseUrl()必须在build()之前调用,其它可以随意。
- platform 指定调用的平台,这里我们使用的是Android.
- callFactory okhttp3的Call.Factory
- baseUrl 请求的root地址
- converterFactories 存储我们自定义的和系统默认提供的convertFactory见上面的A.5
- adapterFactories 存储我们自定义的和系统默认提供的adapterFactory 见上面的A.4
- callbackExecutor 线程调用类
- validateEagerly 为true时做一些预处理操作
2. build()方法的实现
/**
* Create the {@link Retrofit} instance using the configured values.
*
* Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
* OkHttpClient} will be created and used.
*/
//通过配置参数创建一个Retrofit的实例,如果没有配置HttpClient也没有配置CallFactory将采用默认的OkHttpClient
public Retrofit build() {
if (baseUrl == null) {
// baseUrl不能为空
throw new IllegalStateException("Base URL required.");
}
//配置HttpClient,可以看出retrofit默认采用OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//指定callback回调方法的执行器,这里的platform是Android平台,可以看出默认下面的Android--Platform的MainThreadExecutor
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
//将我们自定义的adapterFactory添加到集合中
List adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
//将我们自定义的convertFactory添加到集合中
List converterFactories = new ArrayList<>(this.converterFactories);
// 返回Retrofit
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
复制代码
Android--Platform
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
复制代码
经过build()操作后,我们配置好了一个我们想要的retrofit,接下来我们来看看这些配置是如何生效的,我们通过
GitHubService service = retrofit.create(GitHubService.class);
复制代码
来生成我们service接口的实现类。我们来看create()方法。
3. retrofit.create()
public T create(final Class service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
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 {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod
- validateEagerly 为true时会走 eagerlyValidateMethods(service)
private void eagerlyValidateMethods(Class> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
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做的缓存处理。如果缓存中存在直接返回。
- 接下来我们看见采用了动态代理的模式来创建service接口的实现类。
- 如果是platform的方法直接return
- 如果是我们service接口内的方法,我们看到通过上面的loadServiceMethod(method)来创建了一个ServiceMethod类,我们来看ServiceMethod类做了那些处理。
4. ServiceMethod
我们看到ServiceMethod也是采用Builder模式来构建。
/** Adapts an invocation of an interface method into an HTTP call. */
final class ServiceMethod {
// Upper and lower characters, digits, underscores, and hyphens, starting with a character.
static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
//请求地址中{}的正则匹配表达式
static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
//参数名称的正常匹配
static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);
final okhttp3.Call.Factory callFactory;//okhttp3.Call.Factory
final CallAdapter callAdapter;//返回对象适配器
private final HttpUrl baseUrl;//根地址
private final Converter responseConverter;//reponseBody转换类
private final String httpMethod;//请求方式,PUT,POST...
private final String relativeUrl;//相对地址
private final Headers headers;//请求头
private final MediaType contentType;//请求的Content-Type
private final boolean hasBody;//是否有请求消息体
private final boolean isFormEncoded;//是否进行参数编码
private final boolean isMultipart;// 上传时使用
private final ParameterHandler>[] parameterHandlers;//请求参数注解的封装对象
ServiceMethod(Builder builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod;
this.relativeUrl = builder.relativeUrl;
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
...
}
复制代码
接着来看 build() 方法
public ServiceMethod build() {
// [1] 创建CallAdapter,并得到返回的对象
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
...
//[2] 创建ResponseConverte,对返回的数据进行处理
responseConverter = createResponseConverter();
//[3]遍历方法注解,获取具体的配置参数
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
//[4] 方法中参数注解的处理
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
...
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
...
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);
}
复制代码
上面的ServiceMethod.build()方法大概进行了如下操作:
- [1] 创建CallAdapter,并得到返回的对象
- [2] 创建ResponseConverte,对返回的数据进行处理
- [3] 遍历方法注解,获取具体的配置参数
- [4] 方法中参数注解的处理
接下来我们具体看看是如何实现的
[1] createCallAdapter()
private CallAdapter createCallAdapter() {
//获取方法的完整信息的返回值
Type returnType = method.getGenericReturnType();
...
//获得注解
Annotation[] annotations = method.getAnnotations();
...
return (CallAdapter) retrofit.callAdapter(returnType, annotations);
...
}
复制代码
可以看到实际上是调用了retrofit.callAdapter(returnType, annotations)方法
public CallAdapter, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
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;
}
}
...
}
复制代码
从上面最终调用的nextCallAdapter方法,
adapterFactories.get(i).get(returnType, annotations, this)
看到,最终返回我们添加到adapterFactories的CallAdapterFactory.get()对象就是我们自定义的CallAdapter,注意这里是有排序概念的,排在前面的优先匹配。
再通过responseType = callAdapter.responseType();将我们自己定义的call对象,或Obserable对象,或其他需要类型返回,见上面图A.④。
[2] createResponseConverter()
private Converter 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.responseBodyConverter(responseType, annotations)
public Converter responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public Converter nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
...
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter) converter;
}
}
...
}
复制代码
这里我们最终看到通过converterFactories.get(i).responseBodyConverter(type, annotations, this)方法,返回我们自定义的泛型对象见上面图A.⑤,通常是我们反序列化操作转换后的对象,或根据需要过滤一些数据,返回有用的数据。
[3] parseMethodAnnotation(annotation)
在这里处理方法上面的注解,获取到请求方式见上面图A.②,并对不同的请求方式做相应处理。
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);
if (!Void.class.equals(responseType)) {
throw methodError("HEAD method must use Void as response type.");
}
} 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("@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = 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);
}
复制代码
我们看到这里将获取到的请求方式httpMethod,是否有hasBody,还有地址路径,headers,还有地址中含有的请求参数,等等,都赋值给ServiceMethod.Builder的相应属性。
[4] parameterHandlers[]的赋值操作
在ServiceMethod.Build(Retrofit retrofit, Method method)时我们看一下
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
复制代码
- methodAnnotations 获得method上的所有注解
- parameterTypes 获得所有的参数类型,String ,int ...
- parameterAnnotationsArray 获得参数的注解集合
再看
int parameterCount = parameterAnnotationsArray.length;
//构建一个ParameterHandler集合,
parameterHandlers = new ParameterHandler>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
//获取第p个参数类型
Type parameterType = parameterTypes[p];
...
//获取第p个参数注解集合
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
...
//构建一个ParameterHandler对象
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
复制代码
看看 parseParameter(p, parameterType, parameterAnnotations)
private ParameterHandler> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler> result = null;
for (Annotation annotation : annotations) {
ParameterHandler> annotationAction = parseParameterAnnotation(p, parameterType, annotations,annotation);
}
...
return result;
}
复制代码
接着往下看parseParameterAnnotation(p, parameterType, annotations,annotation)
private ParameterHandler> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
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();
} 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());
} else if (annotation instanceof Query) {
Query query = (Query) annotation;
String name = query.value();
boolean encoded = query.encoded();
Class> rawParameterType = Utils.getRawType(type);
gotQuery = true;
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ ")" );
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).array();
} else {
Converter, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Query<>(name, converter, encoded);
}
} else if (annotation instanceof QueryName) {
QueryName query = (QueryName) annotation;
boolean encoded = query.encoded();
Class> rawParameterType = Utils.getRawType(type);
gotQuery = true;
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ ")" );
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.QueryName<>(converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.QueryName<>(converter, encoded).array();
} else {
Converter, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.QueryName<>(converter, encoded);
}
} else if (annotation instanceof QueryMap) {
Class> rawParameterType = Utils.getRawType(type);
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, "@QueryMap parameter type must be Map.");
}
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(p, "Map must include generic types (e.g., Map)" );
}
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
if (String.class != keyType) {
throw parameterError(p, "@QueryMap keys must be of type String: " + keyType);
}
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
Converter, String> valueConverter =
retrofit.stringConverter(valueType, annotations);
return new ParameterHandler.QueryMap<>(valueConverter, ((QueryMap) annotation).encoded());
} else if (annotation instanceof Header) {
Header header = (Header) annotation;
String name = header.value();
Class> rawParameterType = Utils.getRawType(type);
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ ")" );
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Header<>(name, converter).iterable();
} else if (rawParameterType.isArray()) {
Class> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Header<>(name, converter).array();
} else {
Converter, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Header<>(name, converter);
}
} else if (annotation instanceof HeaderMap) {
Class> rawParameterType = Utils.getRawType(type);
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, "@HeaderMap parameter type must be Map.");
}
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(p, "Map must include generic types (e.g., Map)" );
}
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
if (String.class != keyType) {
throw parameterError(p, "@HeaderMap keys must be of type String: " + keyType);
}
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
Converter, String> valueConverter =
retrofit.stringConverter(valueType, annotations);
return new ParameterHandler.HeaderMap<>(valueConverter);
} else if (annotation instanceof Field) {
if (!isFormEncoded) {
throw parameterError(p, "@Field parameters can only be used with form encoding.");
}
Field field = (Field) annotation;
String name = field.value();
boolean encoded = field.encoded();
gotField = true;
Class> rawParameterType = Utils.getRawType(type);
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ ")" );
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Field<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Field<>(name, converter, encoded).array();
} else {
Converter, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Field<>(name, converter, encoded);
}
} else if (annotation instanceof FieldMap) {
if (!isFormEncoded) {
throw parameterError(p, "@FieldMap parameters can only be used with form encoding.");
}
Class> rawParameterType = Utils.getRawType(type);
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, "@FieldMap parameter type must be Map.");
}
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(p,
"Map must include generic types (e.g., Map)" );
}
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
if (String.class != keyType) {
throw parameterError(p, "@FieldMap keys must be of type String: " + keyType);
}
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
Converter, String> valueConverter =
retrofit.stringConverter(valueType, annotations);
gotField = true;
return new ParameterHandler.FieldMap<>(valueConverter, ((FieldMap) annotation).encoded());
} else if (annotation instanceof Part) {
if (!isMultipart) {
throw parameterError(p, "@Part parameters can only be used with multipart encoding.");
}
Part part = (Part) annotation;
gotPart = true;
String partName = part.value();
Class> rawParameterType = Utils.getRawType(type);
if (partName.isEmpty()) {
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ ")" );
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
if (!MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
throw parameterError(p,
"@Part annotation must supply a name or use MultipartBody.Part parameter type.");
}
return ParameterHandler.RawPart.INSTANCE.iterable();
} else if (rawParameterType.isArray()) {
Class> arrayComponentType = rawParameterType.getComponentType();
if (!MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
throw parameterError(p,
"@Part annotation must supply a name or use MultipartBody.Part parameter type.");
}
return ParameterHandler.RawPart.INSTANCE.array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
return ParameterHandler.RawPart.INSTANCE;
} else {
throw parameterError(p,
"@Part annotation must supply a name or use MultipartBody.Part parameter type.");
}
} else {
Headers headers =
Headers.of("Content-Disposition", "form-data; name=\"" + partName + "\"",
"Content-Transfer-Encoding", part.encoding());
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ ")" );
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
throw parameterError(p, "@Part parameters using the MultipartBody.Part must not "
+ "include a part name in the annotation.");
}
Converter, RequestBody> converter =
retrofit.requestBodyConverter(iterableType, annotations, methodAnnotations);
return new ParameterHandler.Part<>(headers, converter).iterable();
} else if (rawParameterType.isArray()) {
Class> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
if (MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
throw parameterError(p, "@Part parameters using the MultipartBody.Part must not "
+ "include a part name in the annotation.");
}
Converter, RequestBody> converter =
retrofit.requestBodyConverter(arrayComponentType, annotations, methodAnnotations);
return new ParameterHandler.Part<>(headers, converter).array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, "@Part parameters using the MultipartBody.Part must not "
+ "include a part name in the annotation.");
} else {
Converter, RequestBody> converter =
retrofit.requestBodyConverter(type, annotations, methodAnnotations);
return new ParameterHandler.Part<>(headers, converter);
}
}
} else if (annotation instanceof PartMap) {
if (!isMultipart) {
throw parameterError(p, "@PartMap parameters can only be used with multipart encoding.");
}
gotPart = true;
Class> rawParameterType = Utils.getRawType(type);
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, "@PartMap parameter type must be Map.");
}
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(p, "Map must include generic types (e.g., Map)" );
}
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
if (String.class != keyType) {
throw parameterError(p, "@PartMap keys must be of type String: " + keyType);
}
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(valueType))) {
throw parameterError(p, "@PartMap values cannot be MultipartBody.Part. "
+ "Use @Part List or a different value type instead." );
}
Converter, RequestBody> valueConverter =
retrofit.requestBodyConverter(valueType, annotations, methodAnnotations);
PartMap partMap = (PartMap) annotation;
return new ParameterHandler.PartMap<>(valueConverter, partMap.encoding());
} else if (annotation instanceof Body) {
if (isFormEncoded || isMultipart) {
throw parameterError(p,
"@Body parameters cannot be used with form or multi-part encoding.");
}
if (gotBody) {
throw parameterError(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(e, p, "Unable to create @Body converter for %s", type);
}
gotBody = true;
return new ParameterHandler.Body<>(converter);
}
return null; // Not a Retrofit annotation.
}
复制代码
这么超长的代码,将我们方法参数的注解,参数类型,参数值都拿到,封装为 ParameterHandler 并保存到ParameterHandler>[] parameterHandlers集合。
至此,我们将我们创建的service接口所调用方法中的请求方式,请求路径,返回值,请求参数等都获取到了,并存储到一个ServiceMethod对象中。
接下来我们再回到 retrofit.Create() 中
public T create(final Class service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
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 {
...
//这里最终返回到Retrofit中的ServiceMethod,来存储我们构建的serviceMethod
ServiceMethod serviceMethod =
(ServiceMethod) loadServiceMethod(method);
//再看OkHttpCall
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
复制代码
5. OkHttpCall
将我们上面构建的serviceMethod 与参数传进来
OkHttpCall(ServiceMethod serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
复制代码
最后通过serviceMethod.callAdapter.adapt(okHttpCall)就创建好了我们service的一个实现类。
再看看**callAdapter.adapt(okHttpCall)**这里的callAdapter是们自定义的callAdapter对象,Android默认的是Call<>;若设置了RxJavaCallAdapterFactory,返回的则是Observable<>,这里我们看看后一种情况下的实现方式。
RxJavaCallAdapterFactory-->RxJava2CallAdapter 这里我们看RxJava2CallAdapter的adapt()方法。
@Override public Object adapt(Call call) {
Observable> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return observable;
}
复制代码
我们看到但isAsync是异步情况下时,new CallEnqueueObservable<>(call),创建了一个CallEnqueueObservable 对象,并将retrofit的okhttpCall继续传进来.
我们知道在RxJava,Observable的subscribe()触发了代码执行的操作。来看:
@SchedulerSupport(SchedulerSupport.NONE)
@Override
public final void subscribe(Observer super T> observer) {
...
@Override public void enqueue(final Callback callback) {
checkNotNull(callback, "callback == null");
//这里创建一个okhttp3.Call的call对象
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
//这里看到通过createRawCall() 创建返回了一个call
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//实际上就是通过okhttp3.call来请求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callback.onFailure(OkHttpCall.this, e);
}
private void callFailure(Throwable e) {
callback.onFailure(OkHttpCall.this, e);
}
private void callSuccess(Response response) {
callback.onResponse(OkHttpCall.this, response);
...
}
}
复制代码
createRawCall()
private okhttp3.Call createRawCall() throws IOException {
[1] 创建一个request 请求对象
Request request = serviceMethod.toRequest(args);
[2]调用newCall(request)返回一个okhttp3.Call
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
复制代码
serviceMethod.toRequest(args)
Request toRequest(@Nullable Object... args) throws IOException {
//这里new了一个requestBuilder 将我们获取到的请求的相关信息传进去
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
//参数值解析
ParameterHandler[] handlers = (ParameterHandler[]) parameterHandlers;
...
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
//这里调用build()
return requestBuilder.build();
}
复制代码
下面看一下requestBuilder.build() 是如何创建一个request对象的
Request build() {
HttpUrl url;
HttpUrl.Builder urlBuilder = this.urlBuilder;
if (urlBuilder != null) {
url = urlBuilder.build();
} else {
// No query parameters triggered builder creation, just combine the relative URL and base URL.
//noinspection ConstantConditions Non-null if urlBuilder is null.
url = baseUrl.resolve(relativeUrl);
if (url == null) {
throw new IllegalArgumentException(
"Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
}
}
RequestBody body = this.body;
if (body == null) {
// Try to pull from one of the builders.
if (formBuilder != null) {
body = formBuilder.build();
} else if (multipartBuilder != null) {
body = multipartBuilder.build();
} else if (hasBody) {
// Body is absent, make an empty body.
body = RequestBody.create(null, new byte[0]);
}
}
MediaType contentType = this.contentType;
if (contentType != null) {
if (body != null) {
body = new ContentTypeOverridingRequestBody(body, contentType);
} else {
requestBuilder.addHeader("Content-Type", contentType.toString());
}
}
return requestBuilder
.url(url)
.method(method, body)
.build();
}
复制代码
接着看看call.enqueue()
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
复制代码
看client.dispatcher().enqueue(new AsyncCall(responseCallback));
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
//可以看到这里执行了网络请求,并通过call完成返回请求结果的回调。
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
复制代码
从上面可以看到,这里最终是通过创建一个okHttp3.Call对象,构建出一个网络请求的Request,发送网络请求,并调用了call.enqueue()最后将请求到的结果,返回到Retrofit的Callback对象。
package retrofit2;
public interface Callback {
void onResponse(Call call, Response response);
void onFailure(Call call, Throwable t);
复制代码
到这里一个请求就结束了。
总结
梳理一下整个过程:
- 书写我们的service请求接口,配置好请求路径,请求方式,参数配置等。
- 构建我们自定义的convert ,convertAdapter 。
- 构建retrofit对象,并添加我们的convertFactory,converAdapterFactory等。
- 通过retrofit的create()动态代理实现service接口的实现类
- 解析 网络请求接口的注解 配置 网络请求参数
- 通过 网络请求适配器 将 网络请求对象 进行平台适配
- 通过 网络请求执行器 发送网络请求
- 通过 数据转换器 解析服务器返回的数据
- 通过 回调执行器 切换线程(子线程 ->>主线程)
- 最后用户在主线程处理返回结果
参考文章
(参考使用了下面文章的部分内容与资源)
- retrofit 官网
- retrofit 使用教程
- Android:手把手带你 深入读懂 Retrofit 2.0 源码