调用流程
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GithubService service = retrofit.create(GithubService.class);
Call<List<Repo>> repos = service.listRepos("byerman");
repos.enqueue(new retrofit2.Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call,retrofit2.Response<List<Repo>> response) {}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {}
});
目标一:如何完成一个网络请求的基本链路?
1.repos.enqueue(new Callback()) 通过调用Call.enqueue,在内部函数的回调中获得网络请求的结果 等待repos的返回
2.去看一下enqueue内部实现,发现Call是一个接口,所以要去看一下Call是怎么来的?service.listRepos("byerman")
发现listRepos也是一个接口调用,所以去看一下service是怎么来的?retrofit.create(GithubService.class) : 等待service的返回
3.查看create源码
public <T> T create(final Class<T> service) {
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.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
validateServiceInterface(service)
含义:检查service可用性、预加载
- 检查传进来的Class,如果不是接口类,则抛出异常
- 遍历service及其父接口,如果有泛型声明,则抛出异常
- 通过配置validateEagerly 提前解析method,提前发现代码异常
Proxy.newProxyInstance(service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler())
含义:
通过动态代理,当调用目标对象(接口类)的方法时,通过动态代理的invoke方法,获取真实的代理对象并返回给我们
这里我们关注
loadServiceMethod(method).invoke(args) : 返回我们需要真实的Call对象(代理对象)
platoform.invokeDefaultMethod(method,servicec,proxy,args)只是把类的默认方法不处理,直接返回而已
到这里我们的第一条链路就结束了
目标:完成一个网络请求的链路
过程:
repos.enqueue(new Callback()) repos怎么来的?repos:Call对象
service.listRepos->通过动态代理invoke回调类调用实际代理类的方法获取repos
loadServiceMethod(method).invoke(args)返回我们需要的repos(Call)对象
结果:通过调用Call.enqueue,在回调函数中获取返回的数据
目标二:Call是一个接口,enqueue是接口方法,它们内部的具体实现类是怎样的?(目标一的扩展,通过具体实现类才能知道实际是怎么完成网络请求的)
因为这里返回的Call是一个接口,通过上一个分析我们知道
loadServiceMethod(method).invoke(args)可以得到我们需要的Call对象
接下来分析这个方法,首先看invoke
发现是一个抽象的方法,具体实现要找到具体实现类,看里面的invoke的逻辑
所以看loadServiceMethod(method)
这里serviceMehtodCache是一个Map集合(有缓存的作用),key是Method,我们关注没有缓存的情况1
ServiceMethod.parseAnnotations(this,method)
跟踪代码
继续跟踪,我们主要看return方法,细节不急着看,下面的HttpServiceMethod.parseAnnotations最后的代码
可以看到当代码支持kotlin时,返回下面两个内容,我们只关注java,所以看CallAdapted那块内容
这里终于找到ServiceMethod的最终实现类了,但是没发现invoke方法,所以回到HttpServiceMethod看有没有invoke(如无意外肯定有,因为没其他类了)
可以看到我们要找的Call就是OkHttpCall了,然后return的时候调了adapt对call进行处理,返回一个新的Call(这里为了不混淆我们目标,因为跟踪代码后会发现,最后返回的Call还是这个OkHttpCall),所以我们继续看call里面的enqueue方法
这里创建了一个okhttp3的call对象,并把rawCall赋值给它,因为初始化时rawCall是空的,最后createRawCall创建新的Call
最后通过okhttp3的Call.enqueue进行网络请求,在onResponse和onFailed中得到请求结果,并调用我们传进来的callback对象把结果回调出去,至此,整个流程完成,我们可以知道,最后Retrofit也是调用了Okhttp的Call对象enqueue得到结果,整理一下流程图
目标三:adapt(call,args)内部对OkHttpCall做了什么处理,OkHttpCall传入的参数requestFactory, args, callFactory, responseConverter如何生成?
敬请关注下一篇文章内容