网络库浅析

网络方案说明

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模式,配置项包括:

  • <p>支持使用者添加的
  • interceptors - 网络拦截器,用于添加自定义拦截器
  • commonParams - 通用参数,通用参数可以通过添加自定义拦截器添加,也可以将通用参数的键值对加入commonParams
  • commonHeaders - 通用请求头,通用请求头可以通过添加自定义拦截器添加,也可以将通用headers的键值对加入commonHeaders
  • <p>超时相关
  • connectTimeout - 链接超时时长,默认10秒
  • readTimeout - 读取操作超时时长,默认60秒
  • writeTimeout - 写操作超时时长,默认60秒
  • timeUnit - 超时时长的时间单位,默认是秒,@see {@link TimeUnit},会影响上面三个超时时长
  • <p>缓存相关
  • 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等。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 又是一年中秋佳节,祝各位中秋节快乐。 今天我们来聊聊这个最近很火的网络请求库retrofit,在此基础上会延伸出一...
    涅槃1992阅读 7,713评论 13 133
  • 上周四晚上11点过孩子从学校打来电话,两件事情:1、和同学打篮球不小心打坏了同学的眼镜要赔偿100元;2、询问他现...
    陪小天慢慢长大阅读 261评论 2 3
  • 文 | 程安 1、 前几天和插画师一起去吃饭,走在一条风景挺好的人行道上,我忍不住拉着他的手抬头看天空。 突然感觉...
    程安阅读 8,292评论 92 331
  • 今天突然想到了之前一起共事的一个老同志,他刚开始给我的印象特别的好。慢慢的相处久了就发现,其实他也不像我之前想象的...
    喜爱文字阅读 845评论 0 0