前一章节,先系统的讲解了关于Retrofit
实现当中的主要技术动态代理,本篇详细结合动态代理在Retrofit
中的应用,扩展到结合RxJava
来使用html
要深刻研究一款开源项目最好的入口就是它所暴露出来的外部使用接口,按照这个思路,因此须要大致先了解Retrofit
的基本使用,这里就不阐述这些基础的知识,能够查看之前的博客git
RxRetrofit-专栏github
想要弄清楚 Retrofit 的细节,先来看一下 Retrofit 源码的组成:设计模式
一个 retrofit2.http 包,里面所有是定义 HTTP 请求的注解,好比 GET、POST、PUT、DELETE、Headers、Path、Query 等等数组
余下的 retrofit 2.0 包中十几个类和接口就是所有 retrofit 的代码了,代码真的不多,很简单,由于retrofit把网络请求这部分功能所有交给了 okHttp 了缓存
先上一段使用Retrofit开始前的初始代码网络
//手动建立一个OkHttpClient并设置超时时间缓存等设置
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(basePar.getConnectionTime(), TimeUnit.SECONDS);
/*建立retrofit对象*/
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(basePar.getBaseUrl())
.build();复制代码
这里的入口Builder()
方法进入源码ide
public static final class Builder {
private Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private List<Converter.Factory> converterFactories = new ArrayList<>();
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
// 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());
}
public Builder() {
this(Platform.get());
}
xxxx复制代码
Builder类中主要是记录请求过程当中的一些配置信息,好比基础url
,固然重要的是addConverterFactory
方法记录Converter
数据转换器;addCallAdapterFactory
方法记录CallAdapter-HTTP
请求返回数据的类型.工具
Converter
数据转换器Converter
数据转换器默认存放在retrofit-converters
中
Converter
采用接口抽象的方式,灵活了转换器的种类,经常使用的如上图中的Gson
和String
,一样这里能够能够自由扩展,实现Converter.Factory
接口
CallAdapter
请求返回数据的类型工程位置如图
这里同Converter
数据转换器思想同样一样是采用抽象接口的方式,继承CallAdapter.Factory
类实现扩展,正如上图中箭头指示的显示扩展的RxJava2
的扩展
在Builder
记录完数据后经过build()
方法,将收集的信息传递给最后的Retrofit
对象中,而且初始了okhttp3.Call.Factory
请求处理类,从中能够看出Retrofit2.0
底层的http
请求默认就是经过okhttp3
处理的。
/** * Create the {@link Retrofit} instance using the configured values. * <p> * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link * OkHttpClient} will be created and used. */
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}复制代码
Retrofit
初始完成之后,须要调用create
方法传入一个java接口抽象类对象做为参数。其实这一步真是Retrofit
动态代理生成的地方
源码:
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
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();
@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);
}
});
}复制代码
使用代码:
HttpTestService httpService = retrofit.create(HttpTestService.class);
httpService.getAllVedioBy(isAll());复制代码
上面HttpTestService
对象实际上是一个动态代理对象,并非一个真正的 HttpTestService
接口的implements
对象,当 httpService
对象调用 getAllVedioBy
方法时,执行的是下面动态代理方法。
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);复制代码
其中主要ServiceMethod
是主要的处理对象
ServiceMethod
信息类当调用loadServiceMethod
方法,将抽象HttpTestService中经过注解定义的信息收集起来存放于ServiceMethod
中,其中主要包含了一下数据:
OkHttpClient:发送网络请求的工具
RequestFactory: 相似于 Volley 中的 Request,包含了HTTP请求的Url、Header信息,MediaType、Method以及RequestAction数组
CallAdapter:HTTP请求返回数据的类型
Converter:数据转换器
最后Map<Method, ServiceMethod> serviceMethodCache
保存所有的 ServiceMethod
信息类
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}复制代码
debug
可查看当前ServiceMethod
对象收集的信息
收集完信息之后执行了
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);复制代码
这一步对okhttp熟悉的同窗确定知道了,就是经过okhttp请求数据,其中serviceMethod是请求的地址信息,args是当前接口须要的参数信息。
执行完http请求之后,执行了
serviceMethod.callAdapter.adapt(okHttpCall);复制代码
这一步是将okhttp获取到的数据传递给一开始Retrofit
经过builder
指定的RxJavaCallAdapterFactory
类,那它是如何一步步处理的呢?
其实在一开始的获取serviceMethod
方法loadServiceMethod(Method method)
中,已经将Retrofit
对象传递给了serviceMethod
对象
核心代码:
//这里的this便是`Retrofit`对象
result = new ServiceMethod.Builder(this, method).build();复制代码
经过.Builder(this, method).build()
方法将Retrofit
一开始的builder
信息所有传递给了如今的serviceMethod
对象,因此当执行
serviceMethod.callAdapter.adapt(okHttpCall);复制代码
serviceMethod.callAdapter
便制动转换成了RxJavaCallAdapterFactory
,调用CallAdapter
抽象接口adapt
进入到RxJavaCallAdapterFactory
类中
源码:
@Override public <R> Observable<Response<R>> adapt(Call<R> call) {
Observable<Response<R>> observable = Observable.create(new CallOnSubscribe<>(call));
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
}
}复制代码
最后生成RxJava
的Observable
对象,后面经过获得的Observable
对象就是对数据的处理了。
到此基于Retrofit
结合RxJava
源码的解读就完成了,回头看整个过程其实仍是很简单,做者条理清晰理解起来也很简单,一口气终于把Retrofit
大致撸了一遍。
Retrofit
很是巧妙的用注解来描述一个 HTTP
请求,将一个 HTTP
请求抽象成一个 Java
接口,而后用了 Java
动态代理的方式,动态的将这个接口的注解“翻译”成一个 HTTP
请求,最后再执行这个 HTTP
请求
Retrofit
的功能很是多的依赖 Java
反射,代码中其实还有不少细节,好比异常的捕获、抛出和处理,大量的 Factory
设计模式。
Retrofit
中接口设计的恰到好处,在你建立 Retrofit
对象时,让你有更多更灵活的方式去处理你的需求,好比使用不一样的 Converter
、使用不一样的 CallAdapter
,这也就提供了你使用 RxJava
来调用 Retrofit
的可能。