文章目录
以Retrofit2.4为例。
概述
Retrofit适用于Android和Java的类型安全的HTTP客户端。一个RESTful的基于OKHttp的Http网络框架。简单网络请求,提高开发效率。
使用如下
- 定义
Java
接口
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
- 构建
Retrofit
对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
- 生成
Java
接口对象
GitHubService service = retrofit.create(GitHubService.class);
- 调用对象的方法获取对应的
Call
Call<List<Repo>> repos = service.listRepos("octocat");
- 也就是调用
Call
的execute
方法进行同步网络请求,或者调用enqueue
进行异步的网路请求。
接下来我们会根据一一分析这5个步骤。基于Retrofit2.4.0分析。
Java接口定义
由于Retrofit使用的动态代理进行生成接口对象的,我们的网络请求的接口必须是Java接口。
Retrofit定义了许多的注解。定义网络请求的接口就是通过这些注解来完成的。
注解会保留到运行时,因为Retrofit需要根据这些注解去解析运行时的参数。
比如GET注解
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {
String value() default "";
}
GET
方法上的注解,注解保留到运行时。
构建Retrofit对象
使用了Builder
模式来创建Retrofit
对象。Retrofit.Builder
拥有很多创建Retrofit
的配置项,通过这些配置项来创建Retrofit
对象。每个配置项的方法返回Builder
对象,用于.
来进行配置的连接,最后通过build
方法创建Retrofit
。
比如配置baseUrl
:
public static final class Builder {
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
}
检测baseUrl
是否为null
,调用重载的baseUrl
方法。baseUrl(HttpUrl baseUrl)
中检测baseUrl
是否为null
,并且检测url
是否合法,最后赋值给Builder
对象的baseUrl
。最后返回this
。
build
方法:
public static final class Builder {
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
......
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
}
通过此方法返回Retrofit
对象。
这里先不进行配置项相关的说明,后面碰到会说明。
生成Java接口对象
获取接口对象时,是通过Retrofit
的create
方法。
public final class Retrofit {
public <T> T create(final Class<T> 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();
private final Object[] emptyArgs = new Object[0];
@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<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
}
首先调用Utils.validateServiceInterface
方法验证service
。
final class Utils {
static <T> void validateServiceInterface(Class<T> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
if (service.getInterfaces().length > 0) {
throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
}
}
}
此方法验证service
是不是Java
接口,并且验证接口是否继承了其他接口。
接着分析Retrofit
的create
的方法。通过变量validateEagerly
来判断是否调用eagerlyValidateMethods
方法,validateEagerly
表示是否调用create
方法时急切的验证接口中的方法的配置,默认是false
。
接着是创建一个InvocationHandler
匿名内部类对象,调用Proxy.newProxyInstance
的方法来创建一个Java接口对象。这里使用了Java的动态代理的知识。一旦调用Java接口中的方法就会调用到InvocationHandler
中的invoke
方法。
总结:
Retrofit的create方法有两个功能,一是验证接口,一个是通过
Proxy.newProxyInstance
方法生成一个动态代理的Java接口对象。
调用对象的方法获取Call
调用对象的方法会调用到InvocationHandler
匿名对象的invoke
方法。
Call<List<Repo>> repos = service.listRepos("octocat");
我们来分析一下InvocationHandler
匿名内部对象的invoke方法。
public final class Retrofit {
public <T> T create(final Class<T> 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 Object invoke(Object proxy, Method method,
@Nullable Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
}
invoke
有三个参数,proxy
是调用者对象,method
调用的方法,args
调用方法的参数。
首先调用method
的getDeclaringClass
获取声明类是不是Object