网络库浅析

网络方案说明

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的网络方案。这也是我们为什么采用这个方案的原因。想要深刻的理解这个原因,我们需要自行去理解以下几个问题。

  1. 什么是响应式变成?
  2. 什么是类型安全?
  3. Http协议的相关知识。
  4. 问题还有很多,有待大家慢慢发现。

我们的网络库,在上面一些技术的基础上,加入了基于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马上发生改变,不需要任何的信息传递。这种玄而又玄的理想的响应式编程模型,只出现在神奇的量子力学领域,这种现象叫做量子纠缠。


量子纠缠.png

RxJava-Retrofit-OkHttp的关系

RxJava-Retrofit-OkHttp.png

上图描述的是三个库之间的依赖关系,其中OkHttp是基础,Retrofit是桥梁,RxJava表现形式,其中Retrofit对OkHttp具有极强的依赖性。

网络关系图.png

上图是一个网络的职能和相互关系的简单示意图,它们的职能分别如下。

  • OKHttp,负责与网络交互,为Retrofit提供发起网络请求和获得响应数据的方法。
  • Retrofit,负责对接口、参数进行封装,发起网络请求,得到网络数据并以Flowable等形式传递给RxJava。
  • RxJava以Consumer、Subscriber等形式接收Retrofit封装后的Flowable类型的网络数据,并回调到业务层处理。

network网络库

做了这么多的铺垫,下面才要进入正题了,我们看一下网络框架的依赖关系。


network_uml.png

从图上看,整个网络库在关系上并没有非常复杂的相互依赖关系,我们只需要以NetHelper为出发点,就可以理清整个库的逻辑了。

NetHelper有以下一些能力。

  • createClient()
    创建可以添加通用参数、通用Header、自定义拦截器,具备网络缓存功能和支持Https的OKHttpClient对象。
  • createRetrofit()
    可以根据URL的不同,可以创建多个Retrofit对象。
  • request()
    发起网络请求。
  • requestLocalFirst()
    先读取本地缓存数据再发起网络请求。
  • addCommonParams()
    在网络库初始化之后加入通用参数。

NetOptions

NetOptions.png

网络基础配置项,使用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对网络数据进行磁盘缓存。


cache.png

介绍几个比较重要的方法

  • 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
    接口访问成功时,识别缓存设置,保存接口数据。
拦截器工作图.png

后期需要完善的地方

  1. 网络缓存目前只支持按照url进行缓存,如果一个接口在多处调用,缓存数据无法区分。
  2. 先读取本地后请求网络的API需要传入5个参数,使用不方便。
  3. 网络缓存只能保证缓存请求成功的数据,status!=0的错误数据也会缓存。
  4. SSL证书识别认证。
  5. 运行过程中修改通用参数、通用header等。

你可能感兴趣的:(网络库浅析)