文章目录
Retrofit 结合OkHttp构成了当前非常流行的Android的网络框架。而Retrofit对OKHttp进行了一层封装,可能入手的门槛高一点,但是使用习惯以后可以说是非常的简洁和高效。
Retrofit 还可以跟 Rxjava 转化成Obserable,形成了链式编程风格,深得我心。
Retrofit的基本源码流程:
- 动态代理获取Method
- Method从提取出注解参数
- 执行网络操作
- 转换成对应结果
本文不会直接跟着代码走完所有流程,只拿出重要的几点分析。
在开始分析之前,先写个简单的例子,我们申明一个接口 getServiceName
public interface ServiceApi {
@GET
Call<String> getServiceName();
}
下面来看,Retrofit 如何解析ServiceApi并进行网络操作。
Retrofit类定义了几个重要的变量:
// Retrofit
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
Retrofit的第一步就是获取
-
ServiceMethod对应着根据Method解析出的注解、返回的结果类型等,并缓存到了serviceMethodCache,避免每次都需要重新解析
-
callFactory 是okhttp创建call的类
-
baseUrl
-
converterFactories 是一个集合,负责对网络请求的RequestBody 和网络请求结果 ResponseBody的转换,例如我们经常使用的GsonConverterFactory
-
callAdapterFactories 也是一个集合,负责对最后的返回结果的封装或转换,例如我们经常使用的RxJava2CallAdapterFactory
-
callbackExecutor 是负责执行,Android默认执行器是利用handler抛到主线程执行回调结果。所以我们会看到retrofit的结果都在主线程中。
1. 动态代理获取Method
retrofit之所以利用动态代理,有两个目的:
- 可以实例化上面ServiceApi这个接口,直接调用getServiceName进行网络请求;
- 可以通过动态代理拿到对应的Method,也就可以拿到Method上的注解,进行参数解析;
除了这种动态代理的实现方式以外,要想达到一样的效果的就是类似ButterKnife注入框架,在编译时候利用AnnotionProcessor生成ServiceApi实现类。因为是编译期生成,所以不会影响运行效率,但是也会存在其他问题。
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];
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);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
这里直接看最后的一句:
loadServiceMethod(method).invoke(args != null ? args : emptyArgs);