你所需要掌握的okhttp知识

1.1   介绍:

okhttp 是目前Android 使用最广泛的网络框架。从android4.4开始HttpUrlConnection的底层实现采用的是OkHttp。

1.2 调用流程

OkHttp请求过程中最少只需要接触OkHttpClient、Request、Call、Response,但是框架内部进行大量的逻辑处理。 所有的逻辑大部分集中在拦截器中,但是在进入拦截器之前还需要依靠分发器来调配请求任务。

分发器:内部维护队列与线程池,完成请求调配;

拦截器:五大默认拦截器完成整个请求过程。

源码分析
构造:OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
     Call call = okHttpClient.newCall(request);
     call.enqueue(new Callback2() {}
网络请求是通过call,去执行 同步方法execute()或者异步方法enqueue(),但是call 只是一个接口类,具体的看其实现类。那么okHttpClient.newCall()到底new出了什么?

 可以看到其实现类是RealCall,看excute具体实现

 核心代码:client.dispatcher().executed(this);将实际操作抛向了dispatcher.

 dispatcher中将call请求加入到了一个栈

 单从名称就可以看到这个一个正在运行的同步栈。

那么dispatcher的异步方法要稍微复杂一点

 首先会先进行判断,当前运行的异步队列是否超过最大限度,当前请求所在ip请求池个数是否超过限度。

 如果不满足条件,该请求call 只能被加入到异步准备栈中。如果满足添加则会在线程池中进行执行。但是在线程池执行需要该类是实现了runnable,但是RealCall并没有继承runnable,那么在其内部找找看。

的确找到了其内部类,而且还有execute()方法

 在这里我们才看到了具体获取response的地方了,同时也引出了Okhttp 另外一个非常重要的责任链,责任链中有一系列的拦截器来帮助我们得到相应。这里我们就已经结合源码把整体流程大致的梳理了一遍。拦截器的内容跟细节下面继续讲。

 1.3 Keep-Alive

提高网络性能优化,很重要的一点就是降低延迟和提升响应速度。 通常我们在浏览器中发起请求的时候header部分往往是这样的

 keep-alive就是浏览器和服务端之间保持长连接,这个连接是可以复用的。在HTTP1.1中是默认开启的。

1.4 连接复用

连接的复用为什么会提高性能呢? 通常我们在发起http请求的时候首先要完成tcp的三次握手,然后传输数据,最后再释放连接。三次握手的过程可以参考这里 TCP三次握手详解及释放连接过程 一次响应的过程

在高并发的请求连接情况下或者同个客户端多次频繁的请求操作,无限制的创建会导致性能低下。 如果使用keep-alive

1.5 连接池 

ConnectionPool:连接池复用socket

excutor : 线程池,用来检测闲置socket并对其进行清理。 connections : connection缓存池。Deque是一个双端列表,支持在头尾插入元素,这里用作LIFO(后进先出)堆栈,多用于缓存数据。 routeDatabase :用来记录连接失败router

1.6 缓存操作

ConnectionPool提供对Deque<RealConnection>进行操作的方法分别为put、get、connectionBecameIdle、evictAll几个操作。分别对应放入连接、获取连接、移除连接、移除所有连接操作。

 1.7 分发器:异步请求工作流程

Q: 如何决定将请求放入ready还是running?

A:这个问题在上面梳理流程的阶段已经说过了。如果当前正在请求数不小于64放入ready;如果小于64,但是已经存在同一域名主机的请求5个放入ready!

Q: 从ready移动running的条件是什么?

在前面realcall源码中可以找到当每个call请求结束后,将会去执行client.dispatcher().finished(this);

在finished()方法中可以看到,首先会在运行列表中讲刚刚执行完的call remove掉,然后执行了上面红框中的promotecalls()方法。而我们这题的答案也就在里面了。

Q: 分发器线程池的工作行为?

这题的答案其实也在上面,当前一个call请求结束后,将会讲准备栈的请求加入运行栈中,执行其请求,依次循环。无等待,最大并发。后面任务分发也会做更详细的介绍。

1.8 线程池

 当一个任务通过execute(Runnable)方法添加到线程池时:

线程数量小于corePoolSize,新建线程(核心)来处理被添加的任务; 线程数量大于等于 corePoolSize,存在空闲线程,使用空闲线程执行新任务;

线程数量大于等于 corePoolSize,不存在空闲线程,新任务被添加到等待队列,添加成功则等待空闲线程,添加失败:线程数量小于maximumPoolSize,新建线程执行新任务;

 线程数量等于maximumPoolSize,拒绝此任务。

2 HTTP协议重定向与缓存处理

2.1 HTTP重定向

重定向(Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置(如:网页重定向、域名的重定向、路由选择的变化也是对数据报文经由路径的一种重定向)

1、永久重定向       这种重定向操作是永久性的。它表示原 URL 不应再被使用,而应该优先选用新的 URL。搜索引擎机器人会在遇到该状态码时触发更新操作,在其索引库中修改与该资源相关的 URL 。

2、临时重定向       有时候请求的资源无法从其标准地址访问,但是却可以从另外的地方访问。在这种情况下可以使用临时重定向。搜索引擎不会记录该新的、临时的链接。在创建、更新或者删除资源的时候,临时重定向也可以用于显示临时性的进度页面。

3、特殊重定向        使页面跳转到本地缓存的版本当中,是一种手工重定向

2.2 缓存处理

缓存的优势

缓存的使用场景很多,通过它可以将数据通过一定的规则存储起来,再次请求数据的时候就可以快速从缓存中读取了,缓存有以下优势。

 HTTP的缓存机制

1、强制缓存

2、对比缓存

3 高并发请求队列:任务分发

3.2 Dispatcher分发器

对于同步请求,分发器只记录请求,用于判断IdleRunnable是否需要执行 对于异步请求,向分发器中提交请求:在RealCall的enqueue()方法

3.3 原理

 当一个任务通过execute(Runnable)方法添加到线程池时: 线程数量小于corePoolSize,新建线程(核心)来处理被添加的任务;

线程数量大于等于 corePoolSize,存在空闲线程,使用空闲线程执行新任务;

线程数量大于等于 corePoolSize,不存在空闲线程,新任务被添加到等待队列,添加成功则等待空闲线程,添加失败:             线程数量小于maximumPoolSize,新建线程执行新任务;             线程数量等于maximumPoolSize,拒绝此任务。

 3.4 获得响应

在请求需要执行时,通过 getResponseWithInterceptorChain 获得请求的结果: Response

3.5 执行流程 

 

4 责任链模式拦截器设计

 拦截器vs责任链 

1、重试拦截器在交出(交给下一个拦截器)之前,负责判断用户是否取消了请求;在获得了结果之后,会根据响应码判断是否需要重定向,如果满足条件那么就会重启执行所有拦截器。

2、桥接拦截器在交出之前,负责将HTTP协议必备的请求头加入其中(如:Host)并添加一些默认的行为(如:GZIP压缩);在获得了结果后,调用保存cookie接口并解析GZIP数据。

3、缓存拦截器顾名思义,交出之前读取并判断是否使用缓存;获得结果后判断是否缓存。

4、连接拦截器在交出之前,负责找到或者新建一个连接,并获得对应的socket流;在获得结果后不进行额外的处理。

5、请求服务器拦截器进行真正的与服务器的通信,向服务器发送数据,解析读取的响应数据。

RealCall中有多种责任链 ​​​​​

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值