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. OpenJDK 源码阅读之 LinkedList

    概要 类继承关系 java.lang.Object java.util.AbstractCollection<E> java.util.AbstractList<E> java ...

  2. Oracle SQL_杂记

    1. 查询当前用户角色,当前用户下的表权限以及所有用户表权限 desc user_role_privs;select * from user_role_privs; desc user_tab_pri ...

  3. java UUID的解析与应用(转载)

    原文链接:http://www.blogjava.net/feelyou/archive/2008/10/14/234320.html 讨论UUID的定义.分类.应用及生成工具. 什么是UUID? U ...

  4. xcode升级到6.0以后遇到的警告错误 原帖链接http://www.cocoachina.com/bbs/simple/?t112432.html

    Xcode 升级后,常常遇到的遇到的警告.错误,解决方法 从sdk3.2.5升级到sdk 7.1中间废弃了很多的方法,还有一些逻辑关系更加严谨了.1,警告:“xoxoxoxo”  is depreca ...

  5. GO 入门(一)

    1.下载安装go环境          https://golang.org/dl/ 2.检查环境变量配置情况,安装过程中会自动配置:GOROOT    和    Path 3.建立go工作区,并配置 ...

  6. Django中如何实现数据库路由?

    虽然我们提供了数据库的信息,它知道怎么连接数据库,但问题是我们保存里面有很多模型,它不知道哪个模型存到哪个数据库.这就要求我们自己来指定,也就是我们自己来实现一个数据库路由.一个数据库路由是一个拥有4 ...

  7. SAP建数据库索引

    [转]SAP建数据库索引   %_hints  db6 'INDEX("MKPF","MKPF~BUD")'           db6 'INDEX(&quo ...

  8. The PageFactory

    The PageFactory 原文地址:https://github.com/SeleniumHQ/selenium/wiki/PageFactory In order to support the ...

  9. STM32 ~ 查看系统时钟

    调用库函数RCC_GetClocksFreq,该函数可以返回片上的各种时钟的频率 函数原形 void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks) ...

  10. kafka的基本操作

    启动ZooKeeper 打开一个新终端并键入以下命令 - bin/zookeeper-server-start.sh config/zookeeper.properties 要启动Kafka Brok ...