网络方案说明
Android时下最流行的网络方案——“RxJava+Retrofit+OKHttp”,我们先通过官方介绍简单了解一下这几个久仰的大名。
- RxJava
RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.
对于JVM的响应式扩展 ,一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库。 - Retrofit
Type-safe HTTP client for Android and Java by Square, Inc.
针对于Java和Android的类型安全的Http客户端。 - OKHttp
An HTTP+HTTP/2 client for Android and Java applications.
为Android和Java提供的一个兼容Http、Http2协议的客户端。
通过上面的介绍,我们可以得出一个结论。“RxJava+Retrofit+OKHttp”方案,是一个响应式的、类型安全的、兼容Http和Http2的网络方案。这也是我们为什么采用这个方案的原因。想要深刻的理解这个原因,我们需要自行去理解以下几个问题。
- 什么是响应式变成?
- 什么是类型安全?
- Http协议的相关知识。
- 问题还有很多,有待大家慢慢发现。
我们的网络库,在上面一些技术的基础上,加入了基于DiskLruCache的数据缓存方案,所以准确的说,我们的网络方案是“RxJava+Retrofit+OKHttp+DiskLruCache”。
其中响应式编程个非常重要的技术概念,甚至可以说是一种编程思想。所以我们会花费一些时间来说一说。
响应式编程
响应式编程是一种通过异步和数据流来构建事物关系的编程模型。
这是一个非常高度概括的、抽象的、脱离了编程的概念描述,这是一个非常准确概念描述,但是说了和没说一样,完全不知道是什么东西。下面我们看一段代码,帮助我们从最根本的出发点上了解这一模型。
int a = 1;
int b = a + 1;
System.out.println(“b = ”+ b) ; // b=2
a = 10;
System.out.println(“b = ”+ b) ;
这一段代码的运行输出是两个b=2,至于为什么,我们在此不做过多的阐述。这段代码的本意其实是b=a+1,也就是说,不论我们将a的值变成多少,b的值都应该是a+1,也就是说第二次打印的预期结果应该是11。
那么我们马上就想到了以下两个办法。
int a = 1;
int b = a + 1;
System.out.println(“b = ”+ b); // b=2
a = 10;
System.out.println(“b = ”+ (a + 1)) ;
int a = 1;
System.out.println(“b = ”+ b); // b=2
a = 10;
int b = a + 1;
System.out.println(“b = ”+ b) ;
上面两段代码,都达到了我们的目的,那么是不是说这两段代码都是响应式编程呢,其实都不是。我们预期的结果,其实是想维持变量a和变量b的一种关系,b=a+1。那么维持这样一个简单的关系为什么就是一种响应式编程呢,这是因为,在一个稳定的关系下,如果一方发生变化,另一方也会随之而发生改变,就好像是b对a的数值变化产生了响应,这就是所谓的响应式编程。
private int a;
private int b;
public void setA(int a) {
this.a = a;
}
public int getB() {
b = a + 1;
return b;
}
以上的这个例子,可以看做是最简单的响应式编程,调用者在每次通过getB()方法获取数据时,都会参照a当前的值进行计算,也就可以看做是对a的数据变化产生了响应。这是一种b对a的主动响应,a并没有对b进行通知。还有一种方式,就是通过观察者模式a的数值发生改变时,主动通知b。
public class Test {
private int a;
private int b;
private OnAChanged onAChanged;
public void setA(int a) {
this.a = a;
onAChanged.onAChanged(a);
}
public int getB() {
return b;
}
public interface OnAChanged {
public void onAChanged(int a);
}
public void setOnAChanged(OnAChanged onAChanged) {
this.onAChanged = onAChanged;
}
public static void main(String[] args) {
Test test = new Test();
test.setOnAChanged(new OnAChanged() {
@Override
public void onAChanged(int a) {
test.setB(a + 1);
}
});
}
}
经过更加复杂和完善的设计,并且完美的解决的多线程异步、代码耦合等问题,RxJava也就应运而生了。
Ps:响应式编程的思想广泛出现在我们的生活和编码中,但是这种响应本质上是对信息的响应,无非是a发生改变时主动通知b,或者b在需要的时候通过观察a得到信息。其实,理想状态下的响应是不依赖于消息的,a发生改变后,b马上发生改变,不需要任何的信息传递。这种玄而又玄的理想的响应式编程模型,只出现在神奇的量子力学领域,这种现象叫做量子纠缠。
RxJava-Retrofit-OkHttp的关系
上图描述的是三个库之间的依赖关系,其中OkHttp是基础,Retrofit是桥梁,RxJava表现形式,其中Retrofit对OkHttp具有极强的依赖性。
上图是一个网络的职能和相互关系的简单示意图,它们的职能分别如下。
- OKHttp,负责与网络交互,为Retrofit提供发起网络请求和获得响应数据的方法。
- Retrofit,负责对接口、参数进行封装,发起网络请求,得到网络数据并以Flowable等形式传递给RxJava。
- RxJava以Consumer、Subscriber等形式接收Retrofit封装后的Flowable类型的网络数据,并回调到业务层处理。
network网络库
做了这么多的铺垫,下面才要进入正题了,我们看一下网络框架的依赖关系。
从图上看,整个网络库在关系上并没有非常复杂的相互依赖关系,我们只需要以NetHelper为出发点,就可以理清整个库的逻辑了。
NetHelper有以下一些能力。
- createClient()
创建可以添加通用参数、通用Header、自定义拦截器,具备网络缓存功能和支持Https的OKHttpClient对象。 - createRetrofit()
可以根据URL的不同,可以创建多个Retrofit对象。 - request()
发起网络请求。 - requestLocalFirst()
先读取本地缓存数据再发起网络请求。 - addCommonParams()
在网络库初始化之后加入通用参数。
NetOptions
网络基础配置项,使用builder模式,配置项包括:
支持使用者添加的
- interceptors - 网络拦截器,用于添加自定义拦截器
- commonParams - 通用参数,通用参数可以通过添加自定义拦截器添加,也可以将通用参数的键值对加入commonParams
- commonHeaders - 通用请求头,通用请求头可以通过添加自定义拦截器添加,也可以将通用headers的键值对加入commonHeaders
超时相关
- connectTimeout - 链接超时时长,默认10秒
- readTimeout - 读取操作超时时长,默认60秒
- writeTimeout - 写操作超时时长,默认60秒
- timeUnit - 超时时长的时间单位,默认是秒,@see {@link TimeUnit},会影响上面三个超时时长
缓存相关
- cacheSize - 网络缓存文件大小,默认是10M
- cacheDir - 网络缓存文件的路径,默认是context.getCacheDir()+/xes/network;
cache
使用DiskLruCache是因为OKHttp自带的网络缓存只支持GET请求,POST请求无法进行数据缓存。为了对数据缓存进行统一的管理,使用DiskLruCache对网络数据进行磁盘缓存。
介绍几个比较重要的方法
- String createCacheKey(Request request)
根据拦截器中的Request对象生成数据缓存的key,其实就是网络请求的URL,不带参数。 - String createCacheValue(Response response)
根据拦截器中的Response对象生成数据缓存的value,格式是time(long)#responseContent。 - savePostRespones(Request request, Response response)
根据Request和Response对接口数据进行磁盘缓存。
converter
自定义XesConverterFactory代替Retrofit的GsonConverterFactory,达到同事支持String和JsonBean的目的。
https
网络框架支持https请求,目前采用信任所有证书的方案,不进行证书校验。
retrofit_url
历史遗留内容,不作为对外开放的功能,主要作用是通过识别header中的DOMAIN_NAME对url进行动态切换。
interceptor
这是一个比较重要的内容,包含以下一些方面。
- HeadersInterceptor
通过持有NetOptions的commonHeaders属性,拦截请求添加通用header。 - ParamsInterceptor
通过持有NetOptions的commonParams属性,拦截请求添加通用参数。 - LocalCacheInterceptor
无网络时,识别缓存设置,直接拦截请求返回本地缓存数据。 - NetCacheInterceptor
接口访问成功时,识别缓存设置,保存接口数据。
后期需要完善的地方
- 网络缓存目前只支持按照url进行缓存,如果一个接口在多处调用,缓存数据无法区分。
- 先读取本地后请求网络的API需要传入5个参数,使用不方便。
- 网络缓存只能保证缓存请求成功的数据,status!=0的错误数据也会缓存。
- SSL证书识别认证。
- 运行过程中修改通用参数、通用header等。