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机制分析的更多相关文章

  1. LevelDB Cache实现机制分析

    几天前淘宝量子恒道在博客上分析了HBase的Cache机制,本篇文章,结合LevelDB 1.7.0版本的源码,分析下LevelDB的Cache机制. 概述 LevelDB是Google开源的持久化K ...

  2. Volley框架源代码分析

    Volley框架分析Github链接 Volley框架分析 Volley源代码解析 为了学习Volley的网络框架,我在AS中将Volley代码又一次撸了一遍,感觉这样的照抄代码也是一种挺好的学习方式 ...

  3. Volley源码分析(2)----ImageLoader

    一:imageLoader 先来看看如何使用imageloader: public void showImg(View view){ ImageView imageView = (ImageView) ...

  4. Java 动态代理机制分析及扩展

    Java 动态代理机制分析及扩展,第 1 部分 王 忠平, 软件工程师, IBM 何 平, 软件工程师, IBM 简介: 本文通过分析 Java 动态代理的机制和特点,解读动态代理类的源代码,并且模拟 ...

  5. memcache redundancy机制分析及思考

    设计和开发可以掌控客户端的分布式服务端程序是件幸事,可以把很多事情交给客户端来做,而且可以做的很优雅.角色决定命运,在互联网架构中,web server必须冲锋在前,注定要在多浏览器版本以及协议兼容性 ...

  6. OpenRisc-41-or1200的cache模块分析

    引言 为CPU提供足够的,稳定的指令流和数据流是计算机体系结构设计中两个永恒的话题.为了给CPU提供指令流,需要设计分支预测机构,为了给CPU提供数据流,就需要设计cache了.其实,无论是insn还 ...

  7. Volley源码分析一

    Volley源码分析 虽然在2017年,volley已经是一个逐渐被淘汰的框架,但其代码短小精悍,网络架构设计巧妙,还是有很多值得学习的地方. 第一篇文章,分析了请求队列的代码,请求队列也是我们使用V ...

  8. Volley源码分析(一)RequestQueue分析

    Volley源码分析 虽然在2017年,volley已经是一个逐渐被淘汰的框架,但其代码短小精悍,网络架构设计巧妙,还是有很多值得学习的地方. 第一篇文章,分析了请求队列的代码,请求队列也是我们使用V ...

  9. Volley 源码分析

    Volley 源码分析 图片分析 要说源码分析,我们得先看一下官方的配图: 从这张图中我们可以了解到 volley 工作流程: 1.请求加入优先队列 2.从缓存调度器中查看是否存在该请求,如果有(没有 ...

随机推荐

  1. linux查找文件夹下的全部文件里是否含有某个字符串

    查找文件夹下的全部文件里是否含有某个字符串  find .|xargs grep -ri "IBM"  查找文件夹下的全部文件里是否含有某个字符串,而且仅仅打印出文件名称  fin ...

  2. ARM Holdings

    http://en.wikipedia.org/wiki/Advanced_RISC_Machines ARM Holdings  (Redirected from Advanced RISC Mac ...

  3. python--面向对象组合

    面向对象的命名空间 类中的方法   类中的静态属性   对象的属性类的组合应用 面向对象的命名空间 class A: country='中国' a=A() a.name='alex' print(a. ...

  4. JavaScript+Json写的二级联动

    省市区的联动,相当常见 我就不写这么大数据的了,先写个简单的试一试 <!DOCTYPE html> <html> <head> <title></ ...

  5. android-async-http框架

    android-async-http 简单介绍:An asynchronous, callback-based Http client for Android built on top of Apac ...

  6. Unity3d 新建xml 读取xml

    在游戏开发中.Xml常常被用来作为技能配置.地图配置.人物动作配置等配置文件. Unity3d内置的Xml库让我们非常方便地就能够新建Xml和读取Xml. 以下是一个样例,新建了一个Xml文档.而且读 ...

  7. Spark SQL includes a cost-based optimizer, columnar storage and code generation to make queries fast.

    https://spark.apache.org/sql/ Performance & Scalability Spark SQL includes a cost-based optimize ...

  8. Learning Scrapy 中文版翻译 第二章

    为了从网页中提取信息,你有必要对网页的结构做一些了解.我们将快速学习HMTL,HTML数状结构以及用XPath在网页上提取信息 HTML, DOM树结构以及XPath 让我们花一点时间来了解当用户在浏 ...

  9. javascript fetch 跨域请求时 session失效问题

    javascript 使用fetch进行跨域请求时默认是不带cookie的,所以会造成 session失效. fetch(url, { method: 'POST', credentials: 'in ...

  10. jps不显示java进程信息

    本来想自己整理,发现已经有前人整理,并且完美解决了我的问题,故转载,感谢分享 转自:http://trinea.iteye.com/blog/1196400 对于jps较熟悉可以直接查看第二部分的分析 ...