一、整体思路
从使用方法出发,首先是怎么使用,其次是我们使用的功能在内部是如何实现的,实现方案上有什么技巧,有什么范式。全文基本上是对 Retrofit 源码的一个分析与导读,非常建议大家下载 Retrofit 源码之后,跟着本文,过一遍源码。
二、基本用例
2.1 创建 Retrofit 对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
builder 模式,外观模式(门面模式),这就不多说了,可以看看 stay 的 Retrofit分析-经典设计模式案例这篇文章。
2.2 定义 API 并获取 API 实例
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
GitHubService github = retrofit.create(GitHubService.class);
先看定义,非常简洁,也没有什么特别之处,除了两个注解:@GET
和 @Path
。它们的用处稍后再分析,我们接着看创建 API 实例:retrofit.create(GitHubService.class)
。这样就创建了 API 实例了,就可以调用 API 的方法发起 HTTP 网络请求了,太方便了。
但 create
方法是怎么创建 API 实例的呢?
public <T> T create(final Class<T> service) {
// 省略非关键代码
return (T) Proxy.newProxyInstance(service.getClassLoader(),
new Class<?>[] { service },
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// 先省略实现
}
});
}
创建 API 实例使用的是动态代理技术。
简而言之,就是动态生成接口的实现类(当然生成实现类有缓存机制),并创建其实例(称之为代理),代理把对接口的调用转发给 InvocationHandler
实例,而在 InvocationHandler
的实现中,除了执行真正的逻辑(例如再次转发给真正的实现类对象),我们还可以进行一些有用的操作,例如统计执行时间、进行初始化和清理、对接口调用进行检查等。
为什么要用动态代理?因为对接口的所有方法的调用都会集中转发到 InvocationHandler#invoke
函数中,我们可以集中进行处理,更方便了。你可能会想,我也可以手写这样的代理类,把所有接口的调用都转发到 InvocationHandler#invoke
呀,当然可以,但是可靠地自动生成岂不更方便?
2.3 调用 API 方法
获取到 API 实例之后,调用方法和普通的代码没有任何区别:
Call<List<Repo>> call = github.listRepos("square");
List<Repo> repos = call.execute().body();
这两行代码就发出了 HTTP 请求,并把返回的数据转化为了 List<Repo>
,太方便了!
现在我们来看看调用 listRepos
是怎么发出 HTTP 请求的。上面 Retrofit#create
方法返回时省略的代码如下:
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, 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 serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
如果调用的是 Object
的方法,例如 equals
,toString
,那就直接调用。如果是 default 方法(Java 8 引入),就调用 default 方法。这些我们都先不管,因为我们在安卓平台调用 listRepos
,肯定不是这两种情况,那这次调用真正干活的就是这三行代码了(好好记住这三行代码,因为接下来很长的篇幅都是在讲它们 ? ):
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
在继续分析这三行代码之前,我们先看看 Stay 在 Retrofit分析-漂亮的解耦套路 这篇文章中分享的流程图,完整的流程概览建议仔细看看这篇文章: