Volley Cache机制分析
1.http缓存机制
要弄明白volley缓存机制,那么肯定是和浏览器的缓存机制有关了,简单来说volley整套框架要做的事都是模拟浏览器来进行一次次的http交互
1.1.概述
http缓存的是指当Web请求抵达缓存时, 如果本地有“已缓存的”副本,就可以从本地存储设备而不是从原始服务器中提取这个文档。
1.2.与缓存有关的头信息
1.2.1.request:
- Cache-Control: max-age=0 以秒为单位
- If-Modified-Since: Mon, 19 Nov 2012 08:38:01 GMT 缓存文件的最后修改时间。
- If-None-Match: "0693f67a67cc1:0" 缓存文件的Etag值
- Cache-Control: no-cache 不使用缓存
- Pragma: no-cache 不使用缓存
1.2.2.response:
- Cache-Control: public 响应被缓存,并且在多用户间共享
- Cache-Control: private 响应只能作为私有缓存,不能在用户之间共享
- Cache-Control:no-cache 提醒浏览器要从服务器提取文档进行验证
- Cache-Control:no-store 绝对禁止缓存(用于机密,敏感文件)
- Cache-Control: max-age=60 60秒之后缓存过期(相对时间)
- Date: Mon, 19 Nov 2012 08:39:00 GMT 当前response发送的时间
- Expires: Mon, 19 Nov 2012 08:40:01 GMT 缓存过期的时间(绝对时间)
- Last-Modified: Mon, 19 Nov 2012 08:38:01 GMT 服务器端文件的最后修改时间
- ETag: "20b1add7ec1cd1:0" 服务器端文件的Etag值
如果同时存在cache-control和Expires怎么办呢?
优先使用cache-control,如果没有cache-control才考虑Expires
2.Volley缓存机制
1.当你add进来一个request的时候,其会根据request.shouldCache(默认为true)进行分发决定是交给NetworkDispatcher还是CacheDispatcher处理
2.NetworkDispatcher通过Network请求数据, 如果有缓存的头信息,会一起发送给服务器
// Perform the network request.
NetworkResponse networkResponse = mNetwork.performRequest(request);
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
.....
.....
.....
addCacheHeaders(headers, request.getCacheEntry());
.....
.....
.....
}
}
3.解析NetworkResponse
Response<?> response = request.parseNetworkResponse(networkResponse);
在这,得在自定义的request中调用很重要的一个静态方法
HttpHeaderParser.parseCacheHeaders(response)
这个方法主要是将NetworkResponse进行封装成一个Cache.Entry对象
public static Cache.Entry parseCacheHeaders(NetworkResponse response) {
//当前系统时间
long now = System.currentTimeMillis();
Map<String, String> headers = response.headers;
long serverDate = 0;
long serverExpires = 0;
long softExpire = 0;
long maxAge = 0;
boolean hasCacheControl = false;
String serverEtag = null;
String headerValue;
headerValue = headers.get("Date");
if (headerValue != null) {
//服务器时间
serverDate = parseDateAsEpoch(headerValue);
}
//获取Cache-Control信息
headerValue = headers.get("Cache-Control");
if (headerValue != null) {
hasCacheControl = true;
String[] tokens = headerValue.split(",");
for (int i = 0; i < tokens.length; i++) {
String token = tokens[i].trim();
if (token.equals("no-cache") || token.equals("no-store")) {
//不缓存
return null;
} else if (token.startsWith("max-age=")) {
try {
//缓存过期时间(相对时间)
maxAge = Long.parseLong(token.substring(8));
} catch (Exception e) {
}
} else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) {
maxAge = 0;
}
}
}
headerValue = headers.get("Expires");
if (headerValue != null) {
//过期时间(绝对时间)
serverExpires = parseDateAsEpoch(headerValue);
}
//ETag
serverEtag = headers.get("ETag");
// Cache-Control takes precedence over an Expires header, even if both exist and Expires
// is more restrictive.
if (hasCacheControl) {
//软件过期时间
softExpire = now + maxAge * 1000;
} else if (serverDate > 0 && serverExpires >= serverDate) {
// Default semantic for Expire header in HTTP specification is softExpire.
softExpire = now + (serverExpires - serverDate);
}
Cache.Entry entry = new Cache.Entry();
entry.data = response.data;
entry.etag = serverEtag;
entry.softTtl = softExpire;
entry.ttl = entry.softTtl;
entry.serverDate = serverDate;
entry.responseHeaders = headers;
return entry;
}
4.在NetworkDispatcher中,再根据其shouldCache和是否有缓存实体来判断是否要进行缓存操作
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written"); }
5.CacheDispatcher的处理
当收到一个request之后,会先到Cache里面去取,看下是否有缓存,
当出现没有缓存 和 缓存过期的情况就直接丢给NetworkDispatcher来处理;
如果缓存没过期,直接拿到缓存实体丢给request的parseNetworkResponse方法这里调用就和NetworkDispatcher里面处理差不多了;
@Override
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// Make a blocking call to initialize the cache.
mCache.initialize();
while (true) {
try {
// Get a request from the cache triage queue, blocking until
// at least one is available.
final Request<?> request = mCacheQueue.take();
request.addMarker("cache-queue-take");
// If the request has been canceled, don't bother dispatching it.
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
// Attempt to retrieve this item from cache.
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
// Cache miss; send off to the network dispatcher.
mNetworkQueue.put(request);
continue;
}
// If it is completely expired, just send it to the network.
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
// We have a cache hit; parse its data for delivery back to the request.
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
mDelivery.postResponse(request, response);
} else {
// Soft-expired cache hit. We can deliver the cached response,
// but we need to also send the request to the network for
// refreshing.
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
}
}
Volley Cache机制分析的更多相关文章
- LevelDB Cache实现机制分析
几天前淘宝量子恒道在博客上分析了HBase的Cache机制,本篇文章,结合LevelDB 1.7.0版本的源码,分析下LevelDB的Cache机制. 概述 LevelDB是Google开源的持久化K ...
- Volley框架源代码分析
Volley框架分析Github链接 Volley框架分析 Volley源代码解析 为了学习Volley的网络框架,我在AS中将Volley代码又一次撸了一遍,感觉这样的照抄代码也是一种挺好的学习方式 ...
- Volley源码分析(2)----ImageLoader
一:imageLoader 先来看看如何使用imageloader: public void showImg(View view){ ImageView imageView = (ImageView) ...
- Java 动态代理机制分析及扩展
Java 动态代理机制分析及扩展,第 1 部分 王 忠平, 软件工程师, IBM 何 平, 软件工程师, IBM 简介: 本文通过分析 Java 动态代理的机制和特点,解读动态代理类的源代码,并且模拟 ...
- memcache redundancy机制分析及思考
设计和开发可以掌控客户端的分布式服务端程序是件幸事,可以把很多事情交给客户端来做,而且可以做的很优雅.角色决定命运,在互联网架构中,web server必须冲锋在前,注定要在多浏览器版本以及协议兼容性 ...
- OpenRisc-41-or1200的cache模块分析
引言 为CPU提供足够的,稳定的指令流和数据流是计算机体系结构设计中两个永恒的话题.为了给CPU提供指令流,需要设计分支预测机构,为了给CPU提供数据流,就需要设计cache了.其实,无论是insn还 ...
- Volley源码分析一
Volley源码分析 虽然在2017年,volley已经是一个逐渐被淘汰的框架,但其代码短小精悍,网络架构设计巧妙,还是有很多值得学习的地方. 第一篇文章,分析了请求队列的代码,请求队列也是我们使用V ...
- Volley源码分析(一)RequestQueue分析
Volley源码分析 虽然在2017年,volley已经是一个逐渐被淘汰的框架,但其代码短小精悍,网络架构设计巧妙,还是有很多值得学习的地方. 第一篇文章,分析了请求队列的代码,请求队列也是我们使用V ...
- Volley 源码分析
Volley 源码分析 图片分析 要说源码分析,我们得先看一下官方的配图: 从这张图中我们可以了解到 volley 工作流程: 1.请求加入优先队列 2.从缓存调度器中查看是否存在该请求,如果有(没有 ...
随机推荐
- Allegro布线基本操作
转:allegro基本步骤 常见问题 cadence16.5中电源线.地线取消飞线显示 目录: 一.Allegro基本技巧 1.关闭电源和地网络的飞线 2.开启特定NET飞线 3.元器件快速对齐(待完 ...
- Linux Setuid(SUID)和Setgid(SGID) sticky bit
http://www.php100.com/html/webkaifa/Linux/2010/0812/6392.html 1.setuid和setgid的解说 setuid和setgid位是让普通用 ...
- AngularJs 常用
Angularjs开发一些经验总结:http://www.cnblogs.com/whitewolf/archive/2013/03/24/2979344.html 七步从AngularJS菜鸟到专家 ...
- android中的常见对话框
在android中对话框是一种常见的操作,常见的对话框有下面几种: 以下是xml布局文件: <LinearLayout xmlns:android="http://schemas.an ...
- Active Directory虚拟机搭建域控服务器环境
前言 还是和上一章一样,痛苦过后还是记录下给后来人提供便利为妙. 虚拟机选择:建议Hyper-V或者VMware 系统选择:建议WIindows Server 2003及以上 我这里是使用VMware ...
- IOS UIWebView 随记
UIWebView中加载的网页尺寸太大,如何让网页适应屏幕大小 webview.scalesPageToFit = YES;
- Nginx+ffmpeg的HLS开源server搭建配置及开发具体解释
本文概述: 至眼下为止.HLS 是移动平台上很重要并十分流行的流媒体传输协议.做移动平台的流媒体开发,不知道它不掌握它 .真是一大遗憾.而HLS的平台搭建有一定的难度,本文针对对该方向有一定了解的朋友 ...
- javascript中提高代码的封装性
我出的面试题中,有一条是问如何避免页面引用JS,出现函数.变量重复.冲突的. 从大的方面讲,应该引入javascript的模块化开发,符合AMD规范之类: 从小的方面说,大概就是限定变量和函数的作用域 ...
- MySql in子句 效率低下优化(亲测有效,从200秒变1秒)
MySql in子句 效率低下优化 背景: 更新一张表中的某些记录值,更新条件来自另一张含有200多万记录的表,效率极其低下,耗时高达几分钟. update clear_res set candele ...
- HDOJ 4704 Sum 规律 欧拉定理
规律 欧拉定理: 找规律 2^n-1 ,n 非常大用欧拉定理 Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/13 ...