Volley理解
概述
物理质量
- 使用Volley 需要Volley.jar(120k),加上自己的封装最多140k。
- 使用OkHttp需要 okio.jar (80k), okhttp.jar(330k)这2个jar包,总大小差不多400k,加上自己的封装,差不多得410k。
Volley 的优点
- 非常适合进行数据量不大,但通信频繁的网络操作
- 可直接在主线程调用服务端并处理返回结果
- 可以取消请求,容易扩展,面向接口编程
- 网络请求线程NetworkDispatcher默认开启了4个,可以优化,通过手机CPU数量
- 通过使用标准的HTTP缓存机制保持磁盘和内存响应的一致
Volley 的缺点
- 使用的是httpclient、HttpURLConnection
- 6.0不支持httpclient了,如果想支持得添加org.apache.http.legacy.jar
- 对大文件下载 Volley的表现非常糟糕
- 只支持http请求
- 图片加载性能一般

对于这张图我们只需要知道:
- Volley 运行的过程中一共有三种线程,包括 UI 线程、Cache 调度线程和 NetWork 调度线程池
- 请求加入优先级队列,Cache 线程进行筛选,如果命中(hit)分发给 UI 线程
- 未命中(miss)交给 NetWork 调度线程池处理,取回后更新 Cache 并分发给 UI 线程
- 每次请求执行过程始于 UI 线程, 终于 UI 线程

RequestQueue封装了众多重要参数,重点有缓存队列,网络请求队列,cache,network,缓存调度,网络调度数组。
流程全部在图中。
- 当一个RequestQueue被成功申请后会开启一个CacheDispatcher和4个默认的NetworkDispatcher。
- CacheDispatcher缓存调度器最为第一层缓冲,开始工作后阻塞的从缓存序列mCacheQueue中取得请求;对于已经取消的请求,标记为跳过并结束这个请求;新的或者过期的请求,直接放入mNetworkQueue中由N个NetworkDispatcher进行处理;已获得缓存信息(网络应答)却没有过期的请求,由Request的parseNetworkResponse进行解析,从而确定此应答是否成功。然后将请求和应答交由Delivery分发者进行处理,如果需要更新缓存那么该请求还会被放入mNetworkQueue中。
- 将请求Request add到RequestQueue后对于不需要缓存的请求(需要额外设置,默认是需要缓存)直接丢入mNetworkQueue交给N个NetworkDispatcher处理;对于需要缓存的,新的请求加到mCacheQueue中给CacheDispatcher处理;需要缓存,但是缓存列表中已经存在了相同URL的请求,放在mWaitingQueue中做暂时处理,等待之前请求完毕后,再重新添加到mCacheQueue中。
- 网络请求调度器NetworkDispatcher作为网络请求真实发生的地方,对消息交给BasicNetwork进行处理,同样的,请求和结果都交由Delivery分发者进行处理。
- Delivery分发者实际上已经是对网络请求处理的最后一层了,在Delivery对请求处理之前,Request已经对网络应答进行过解析,此时应答成功与否已经设定;而后Delivery根据请求所获得的应答情况做不同处理;若应答成功,则触发deliverResponse方法,最终会触发开发者为Request设定的Listener;若应答失败,则触发deliverError方法,最终会触发开发者为Request设定的ErrorListener;处理完后,一个Request的生命周期就结束了,Delivery会调用Request的finish操作,将其从mRequestQueue中移除,与此同时,如果等待列表中存在相同URL的请求,则会将剩余的层级请求全部丢入mCacheQueue交由CacheDispatcher进行处理。
缓存类
Volley的缓存,主要是通过DiskBasedCache实现的。DiskBasedCache类,继承于Cache接口。DiskBasedCache保存CacheHeader,具体的数据并不会全部缓存到内存中(只有一个CacheHeader)。
在初始化时,会先把存在的cache(CacheHeader)保存进mEntries。
可以从get方法看出,先从mEntries找到CacheHeader,再去读文件,根据entry.toCacheEntry(data);构建出Entry类对象。
|
|
Cache接口及静态内部类Entry
|
|
有人说Volley的缓存替换策略是FIFO的,不是LRU。我看了下源码,似乎不是这样(如果我弄错了,希望各位指正)
FIFO 说法来源 Volley HTTP 缓存机制 手撕 Volley(二)
DiskBasedCache中的相关属性方法
|
|
缓存添加
缓存的添加逻辑在NetworkDispatcher.java中展开
|
|
Volley对于图片加载做了内存缓存的处理(ImageLoader),详情见Volley图片加载功能
补充
softTtl和ttl
看上面的代码就知道它们的计算略有不同,stale-while-revalidate这个cache字段是RFC-5861增加的。
对应两个函数refreshNeeded()和isExpired()并不完全相同,分别比较softTtl和ttl值。这可以用于实现从缓存请求的语义,对于softTtl,你将返回一个响应即使是“软”到期,但是会去网络和刷新,如果数据已经改变了返回一个新的响应。
看一下CacheDispatcher类。这里先看ttl有没有过期,过期直接走网络请求响应;没有过期看softTtl,softTtl也没用过期那就完全没过期,过期了也没事,两步走,先返回响应,再去网络请求下,这时候发现过期会再刷新(对这次请求似乎没有影响?未求证),一般不建议使用。
|
|
优秀的参考链接
手撕Volley(一、二、三)
Volley HTTP 缓存机制
Volley图片加载功能
彻底弄懂HTTP缓存机制及原理
浅谈浏览器http的缓存机制
Android史上最全面试题(持续更新ing)
What‘s the different of entry.softTtl and entry.ttl in volley?