Retrofit2出自大名鼎鼎的Square公司,使我们以Java接口及注解的形式来完成Http请求,其简洁明了结构清晰的写法,让人爱不释手。之前也有过使用Retrofit2,当时也是只处于会用的形式,很多地方只是一知半解,今天呢,再来回顾一下,探究一下具体的使用与原理。
简单示例
根据官网文档说明
- 我们先创建一个Java接口
public interface GitHubService {
@GET("users/{user}/repos") //get后面括号这一部分表示具体的路径地址
Call> listRepos(@Path("user") String user);
}
- 创建Retrofit的实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/") //网络请求的baseUrl
.build();
- 行网络请求,获得返回数据
//通过retrofit创建GitHubService的动态代理
GitHubService service = retrofit.create(GitHubService.class);
//通过代理调用相应方法
Call> repos = service.listRepos("octocat");//进行请求并返回数据
通过以上3步,我们就可以进行一次Get
请求,这是怎么实现的呢?稍后我们来一步步的进行探究。
使用详解
在上述示例中,我们进行了一个简单的get请求,其中用到了2个注解
@Get就表示请求类型为get
请求,@path表示的请求路径中的占位符
,
例子中的最终请求链接为 https://api.github.com/users/octocat/repos
,这个是怎么得到的呢 ?
在第2步创建retrofit的实例中,我们可以看到这是使用了一个建造者模式来完成retrofit实例的创建。
就先看一下build方法吧,简单说就是把所有配置信息整合起来,完成retrofit实例的构建:
public Retrofit build() {
if (baseUrl == null) { //1. 必须设置baseUrl 要不直接报错
throw new IllegalStateException("Base URL required.");
}
//2.设置callFactory,如果没有设置的话默认使用okhttpclient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//用来线程任务 ,android默认在主线种执行
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 添加默认的Call适配器 用于请求
// Make a defensive copy of the adapters and add the default Call adapter.
List callAdapterFactories = new ArrayList<>(this.callAdapterFactories); callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
List converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
//添加数据转换器,用于将网络请求返回的结果转换成我们需要的类型 用于处理返回数据
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
}
注解类型的分类
这里我们可以根据API文档来查看,发现Retrofit仅仅有数十个类
通过上以2图可以发现,图一(左图)是具体实现相关的类,图二(右图)全是http请求相关的注解类。
这里我们先对这些注解进行一个分类,根据这些注解类的功能及描述,可以分为三大类如下表所示
- 请求方法的类型:
GET POST
PUT
PATCH
DELETE
OPTIONS
HEAD //以上这7个分别对应http中的网络请求方法
HTTP //可以使用此方法来替代以上7个方法
- 标记类型
FormUrlEncoder
Multipart
Streaming
- 请求参数类型
Body、
Field、FieldMap、
Header、Headers、HeaderMap、
Part、PartMap、
Path、
Query、QueryMap、QueryName、
Tag、
Url
想想整个请求过程大概是这样:
- 定义api接口类,使用注解定义请求方法及所需要的参数信息
- 创建retrofit的实例对象,进行一个基本公共信息配置,也可以提前
- 通过retrofit实例,创建api接口类的动态代理类
- 解析api接口类中的所有方法及注解信息
- 根据注解信息,构造出真实的请求call信息
- 通过生成的代理类,调用相应的请求方法获得返回数据
解释:
其中第一环节主要是根据注解定义请求方法与参数,这里主要涉及到retrofit中注解的运用
第二环节主要是配置公共信息,这里用的最多的就是addConverterFactory()与addCallAdapterFactory()
针对返回数据和请求进行转换适配,常用的 就是gson、rxjava
第三环节是重中之重,这个环节搞明白了retrofit基本上也就搞通了:
public T create(final Class service) {
//验证接口类(主要是验证service是否是接口及接口 其类型参数类型是否支持 以及是否提前获取ServiceMethod)
validateServiceInterface(service);
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class>[]{service},
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable
Object invoke(Object proxy, Method method,
@Nullable Object[] args) throws Throwable {
// If the method is a method from Object then defer to normal invocation.
//如果是Object 直接调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//如果是默认方法 也直接调用
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//关键方法
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
//通过接口类中的Method,解析上面的注解信息,获取转换之后的ServiceMethod
//每一个方法 都对应一个 servicemethod
ServiceMethod> loadServiceMethod(Method method) {
//先从缓存中取
ServiceMethod> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//未获取的话 通过retrofit实例 和 method 来完成注解解析
result = ServiceMethod.parseAnnotations(this, method);
//缓存起来
serviceMethodCache.put(method, result);
}
}
return result;
}
static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {
//解析method中的 方法注解信息 构建请求信息RequestFactory
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.");
}
//根据retrofit,method,requestFactory 获取servicemethod ,
//这个里面已经对对请求 和返回类型进行了适配
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);//⑵
}
解析注解构建请求信息(方法上面的注解和参数里面的注解)
先看一下第一处·RequestFactory.parseAnnotations(retrofit, method);
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
又是一个建造者模式,再具体看一下,Builder
方法的具体信息和build
方法
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations(); //1.获取方法上的注解信息
this.parameterTypes = method.getGenericParameterTypes();//2.获取方法上面的返回参数类型
this.parameterAnnotationsArray = method.getParameterAnnotations();//3.获取方法上面的参数注解信息
}
RequestFactory build() {
//遍历方法中的所有注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...省略
int parameterCount = parameterAnnotationsArray.length; //参数注解的长度
parameterHandlers = new ParameterHandler>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);//解析参数注解信息 并返回一个处理器
}
...省略
return new RequestFactory(this);
}
这里面又暴露出来2个关键方法parseMethodAnnotation
与parseParameter
parseMethodAnnotation
实际就是解析方法上面的注解信息,比如使用的哪种请求方式,请求路径,header信息等
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);
} 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(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse); //解析header注解信息
} else if (annotation instanceof Multipart) { //multipart 与 formUrlencoded 互斥
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
parseHttpMethodAndPath
方法主要就是
- 获取请求方式,
- 是否有请求体,
- 以及检查注解值(请求url)中是否带有?,以及问号后面是否有key-value
- 如果问号后面带有类似?key=value的情况抛错,使用@query
- 获取请求url(使用的是相对路径)
- 以及url中是否有使用
{}
括起来的路径占位符
parseParameter
主要就是解析method中的参数注解信息
private @Nullable
ParameterHandler> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
//解析方法中的参数注解信息 获得相应参数处理器 比如@path @query ...
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(method, p,
"Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
}
return result;
}
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); //⑴
第(1)处的讲解主要就在上面了,下面看关键的核心方法(2)
HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);//⑵
根据构建好的请求信息及方法来适配真正的请求和请求返回数据的相应转换
static HttpServiceMethod parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
//方法上面的注解
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) { //暂时不看kotlin
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType = Utils.getParameterLowerBound(0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
//根据注解和返回类型 构建callAdapter
CallAdapter callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); //(1)
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response)");
}
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
Converter responseConverter = createResponseConverter(retrofit, method, responseType); //(2)
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod) new SuspendForResponse<>(requestFactory,
callFactory, responseConverter, (CallAdapter>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod) new SuspendForBody<>(requestFactory, callFactory, responseConverter, (CallAdapter>) callAdapter, continuationBodyNullable);
} //(3)
}
上述方法主要就是构建ServiceMethod,里面最主要的就是进行请求Call的适配和返回数据类型转换的适配
代码(1)处CallAdapter
就是根据方法返回类型和注解信息构建CallAdapter,
代码(2)处Converter
就是根据返回Call的返回数据和方法来进行数据转换,以转换成我们所需要的类型.
代码(3)处 就是根据前而2处构建HttpServiceMethod,最后在代码调用之处 调用 生成代理类的代理方法完成请求.
- 跟踪
createCallAdapter
会发现最终代码执行到了nextCallAdapter
方法,这里会根据构建的retrofit实例中的callAdapterFactories与返回类型、注解信息 找到合适的适配器
public CallAdapter, ?> nextCallAdapter(
@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
Objects.requireNonNull(returnType, "returnType == null");
Objects.requireNonNull(annotations, "annotations == null");
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());
}
- 同理跟踪代码
createResponseConverter
分发现代码最终执行到了nextResponseBodyConverter
方法,这里会将callAdapter的返回数据和方法所需要的返回类型及注解信息,找到合适的数据转换器
public Converter nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
Objects.requireNonNull(type, "type == null");
Objects.requireNonNull(annotations, "annotations == null");
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;
}
}
... 省略
throw new IllegalArgumentException(builder.toString());
}
第四环节就是直接调用代理类的代理方法获得返回数据再进行处理了
loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
调用方法时,会执行代理类(HttpServiceMethod)的invoke方法,
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解)