1,OkHttp介绍
OkHttp是当前Android使用的流行的网络框架
支持Http/2并允许对同一个主机的所以请求采用同一个套接字
如果非Http/2,则通过连接池,减小请求延迟
默认请求GZip压缩数据
响应缓存,避免了重复请求
请求失败自动重试主机的其他Ip,自动重定向
2,OkHttp的使用
3,OkHttp的调用
同步请求
只是不去调用promoteCalls()方法
异步请求流程
OkHttp请求过程,最少只需要接触OkHttpClient,Request,Call,Response,但是框架内部帮助我们实现了很多逻辑,所有的逻辑大部分集中在拦截器中,但进入拦截器之前还需要调度器来调配请求任务。
分发器:内部维护队列和线程池,完成请求调配
拦截器:完成整个请求过程
分发器:
Dispatcher分发器中的enqueue方法中回去判断,请求会加入到正在执行的队列(running AsyncCall)还是准备执行队列(readyAsyncCall)
判断条件:
// 正在请求的异步个数不大于设定的请求个数(默认是64)
runningAsyncCall.size() < maxRequests
//同一个域名的请求数不大于5个
runningCallForHost(call) maxRequestPerHost
正在执行的请求:RunningAyncCalls.add(call)
线程池跑任务:executorService.excute(call)
判断一个请求任务从readyAsyncCall转移到runningAsyncCall中
判断条件:
RealCall中execute方法
线程执行起来就会去跑RealCall中的excute()方法,
excute方法中回去执行:
// 执行请求
Response response = getResponseWithInterceptorChain()
在try{}catch{}finall{}中最终会执行client.dispathcher().finshed()
在finshed()方法中会将执行完的任务remove()掉,导致正在运行的任务减少,进而回去执行promoteCalls(),在会去判断同一域名的请求小于最大请求数,就会执行runningAsyncCalls.add (call)从readAsyncCall队列中添加一个到runningAsyncCall中去。
executorService线程池中ExcutorService.executorService()方法中,回去new一个线程池
executorService = new ThreadPoolExecutor(0, Inter.MAX_VALUE, 60, TimeUnit_SECONDs, new SynchronousQueue(), Unit.ThreadFactory("OKHttp Dispcher"), false)
线程池参数: 核心线程数, 最大线程数, 闲置时间, 任务队列, 线程创建工厂
核心线程数: 如设置x个核心线程数,一直维护X个核心线程
最大线程数: 同时执行最大的线程数量
闲置时间: 如设置60s,空闲了60s的核心线程数的线程会被回收
任务队列: 见下面详解
创建线程池的队列是等待执行的队列
// 没有容量,只能去判断Inter的最大值, 无等待,最大并发
SynchronousQueue<Runnable> queue = new SynchronousQueue()
// 后发起的请求有可能先执行,容量设置没办法确认是多大,如果不传容量,默认是Inter的最大值,只是和ArrayBlockQueue的数据结构不同
LinkedBlockQueue<Runnable> queue = new LinkedBlockQueue()
// 后发起的请求有可能先执行,容量设置没办法确认是多大,如果不传容量,默认是Inter的最大值
ArrayBlockQueue<Runnable> queue = new ArrayBlockQueue()
当一个任务通过execute(Runnable)方法添加到线程池
线程数量小于corePoolSize, 新建线程(核心)来处理被添加的任务
线程数量大于corePoolSize, 新任务被添加到等待队列, 添加失败
线程数量小于maxmumPoolSize,新建线程来执行新任务
数量等于maxmumPoolSize, 使用RejectedExcutionHandle拒绝策略(默认拒绝策略就是抛出一个异常)
4, OkHttp中拦截器
责任链模式: 对象行为模型,为请求创建一个接收者对象的链,在处理请求的时候执行对应的链,责任链上的处理者负责处理请求,客户只需要把请求发送到责任链即可,无需关心请求的处理细节和数据的传递,所以责任链将请求的发送者和处理者解耦
Response response = getResponseWithInterceptorChain()
getResponseWithInterceptorChain方法中
List<interceptor> interceptor = new ArrayList<>()
// 自定义的拦截器加入到集合中
interceptor.addAll(client.interceptors())
// 重定向拦截器
interceptor.add(retryAndFllowUpInterceptor)
// 桥连拦截器
interceptor.add(new BridgeInterceptor(client.cookieJar()))
// 开始执行缓存拦截器
interceptor.add(new CacheInterceptor(client.interceptorCache()))
// 连接拦截器
interceptor.add(new ConnectInterceptor(client))
// 网络拦截器
interceptor.addAll(new NetworkInterceptors())
// 请求服务器拦截器
interceptor.add(new CallServerInterceptor(forWebSocket))
请求是从上向下一层一层传递,响应从下往上,最终建立一个Socket连接,把我们的http报文写出去,从服务器读取响应response
重定向与重试拦截器:在交给下一个拦截器之前,负责判断用户是否取消了请求,在获得结果之后会根据响应码去判断是否需要重定向,如果满足就会重启执行所有拦截器
重试:
桥连拦截器: 在交给下一级拦截器之前,负责将http协议必备的请求头加入其中(eg:Host), 并添加一些默认的行为(eg: GZIP),在获得结果之后,保存cookie接口,并解析GZIP数据
缓存拦截器: 交给下一级之前,判断是否使用缓存,获得结果后判读是否缓存
缓存策略:拦截器通过CacheStrategy判断使用缓存或者网络请求,此对象的netWorkRequest和cacheResponse分别代表发起请求或者直接使用缓存
networkRequest如果存在优先发起网络请求,否则使用cacheResponse缓存,若都不存在则请求失败
**缓存检测**
连接拦截器: 交给下一级之前,负责找到或者新建一个连接,并获得对应的Socket流,在获得后不进行额外的操作
连接池清理
请求服务器拦截器: 进行真的的与服务器之间的通信,向服务器发送数据,解析读取的响应数据
桥连拦截器完成之后,请求的报文heads才算完整
执行流程