Volley 数据缓存分析

原创 2016年09月06日 19:48:49

1.缓存使用前提:

服务器必须支持,缓存,配置Cache-Control等头信息,因为Volley需要从这些头信息判断缓存是否已经过期。以及一些其他Header的参数

https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.32 http协议文档

预设问题:

1.缓存机制

2.是如何实现的-技术方案。

3.缓存位置(读/写方式)。

4.缓存更新方式!缓存多长时间

2 .Volley官方提供的流程图

这里写图片描述

                       (图1) volley缓存机制

Volley缓存实现,需要服务端进行配合,根据request—-response 中交互的 http中具体Header 字段。例如下图

这里写图片描述
(图2) Http请求的头
当然不止这一种:blog

HTTP头的Expires与Cache-control

request时用到:
| "no-cache"
| "no-store"
| "max-age" "=" delta-seconds
| "max-stale" [ "=" delta-seconds ]
| "min-fresh" "=" delta-seconds
| "no-transform"
| "only-if-cached"
| "cache-extension"
response时用到:
| "public"
| "private" [ "=" <"> field-name <"> ]
| "no-cache" [ "=" <"> field-name <"> ]
| "no-store"
| "no-transform"
| "must-revalidate"
| "proxy-revalidate"
| "max-age" "=" delta-seconds
| "s-maxage" "=" delta-seconds
| "cache-extension"

具体细节下面进行分析

3.具体缓存存放的位置,是在首次初始化传入进去的。context.getCacheDir()。当然可以随意修改存储位置,做好相应的容错即可。

缓存字段主要在HttpHeaderParser 中进行定义,并进行包装内部类Entity结构

        long serverDate = 0;
        long lastModified = 0;
        long serverExpires = 0;
        long softExpire = 0;
        long finalExpire = 0;
        long maxAge = 0;
        long staleWhileRevalidate = 0;
        boolean hasCacheControl = false;
        boolean mustRevalidate = false;

当然这些字段都是可以在Http 协议中Header 找到对应的字段。缓存内容也是这些字段
Cache 接口的实现类有两个 NoCache 和 DiskBasedCache,前一个是空实现。DiskBasedCache进行具体的缓存逻辑

这里写图片描述

             (图3) Cache接口结构

在网络请求成功地方进行缓存,key= request url ,entry为具体response相应封装后的实体

/**
 * Puts the entry with the specified key into the cache.
 * 在网络请求成功中进行缓存
 */
@Override
public synchronized void put(String key, Entry entry) {
    pruneIfNeeded(entry.data.length);
    File file = getFileForKey(key);
    try {
        BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(file));
        CacheHeader e = new CacheHeader(key, entry);
        boolean success = e.writeHeader(fos);
        if (!success) {
            fos.close();
            VolleyLog.d("Failed to write header for %s", file.getAbsolutePath());
            throw new IOException();
        }
        fos.write(entry.data);
        fos.close();
        putEntry(key, e);
        return;
    } catch (IOException e) {
    }
    boolean deleted = file.delete();
    if (!deleted) {
        VolleyLog.d("Could not clean up file %s", file.getAbsolutePath());
    }
}

1.首先进行判断缓存内容是否超过限制的最大容量,超过了就需要清除排在队列最前面的缓存数据
2.根据一些规则生成文件名,并以文件的形式进行返回
3.将key,entity 包装成DiskBasedCache 内部类 CacheHeader结构
4.通过OutputStream 序列化到本地文件中

下面是写入的方式

/**
 * Writes the contents of this CacheHeader to the specified OutputStream.
 */
public boolean writeHeader(OutputStream os) {
    try {
        writeInt(os, CACHE_MAGIC);
        writeString(os, key);
        writeString(os, etag == null ? "" : etag);
        writeLong(os, serverDate);
        writeLong(os, lastModified);
        writeLong(os, ttl);
        writeLong(os, softTtl);
        writeStringStringMap(responseHeaders, os);
        os.flush();
        return true;
    } catch (IOException e) {
        VolleyLog.d("%s", e.toString());
        return false;
    }
}

缓存的读取同样根据 key去拿对应的Entity内容。下面是读取缓存的源码

/**
 * Returns the cache entry with the specified key if it exists, null otherwise.
 */
@Override
public synchronized Entry get(String key) {
    CacheHeader entry = mEntries.get(key);
    // if the entry does not exist, return.
    if (entry == null) {
        return null;
    }

    File file = getFileForKey(key);
    CountingInputStream cis = null;
    try {
        cis = new CountingInputStream(new BufferedInputStream(new FileInputStream(file)));
        CacheHeader.readHeader(cis); // eat header
        byte[] data = streamToBytes(cis, (int) (file.length() - cis.bytesRead));
        return entry.toCacheEntry(data);
    } catch (IOException e) {
        VolleyLog.d("%s: %s", file.getAbsolutePath(), e.toString());
        remove(key);
        return null;
    } finally {
        if (cis != null) {
            try {
                cis.close();
            } catch (IOException ioe) {
                return null;
            }
        }
    }
}

1.根据生成文件名的方式,拿到存入文件对应的路径,
2.BufferedInputStream 进行读流,然后逆序转换为Cache.Entity

下面是对缓存文件的源码

/**
 * Reads the header off of an InputStream and returns a CacheHeader object.
 *
 * @param is The InputStream to read from.
 * @throws IOException
 */
public static CacheHeader readHeader(InputStream is) throws IOException {
    CacheHeader entry = new CacheHeader();
    int magic = readInt(is);
    if (magic != CACHE_MAGIC) {
        // don't bother deleting, it'll get pruned eventually
        throw new IOException();
    }
    entry.key = readString(is);
    entry.etag = readString(is);
    if (entry.etag.equals("")) {
        entry.etag = null;
    }
    entry.serverDate = readLong(is);
    entry.lastModified = readLong(is);
    entry.ttl = readLong(is);
    entry.softTtl = readLong(is);
    entry.responseHeaders = readStringStringMap(is);

    return entry;
}

何时需要更新缓存,以及如何进行缓存清理。

/* True if a refresh is needed from the original data source. /
public boolean refreshNeeded() {
return this.softTtl < System.currentTimeMillis();
}

根据服务端返回值,进行判断,是否需要刷新缓存。设置参数为true

/ Mark the response as intermediate.
response.intermediate = true;

Request时可以动态设置是否进行响应缓存

public final Request<?> setShouldCache(boolean shouldCache) {
    mShouldCache = shouldCache;
    return this;
}

引用1: https://segmentfault.com/q/1010000004711321 Volley源码中ImageLoader类的batchResponse方法的实现问题
引用2:http://blog.csdn.net/soft_po/article/details/51511546 Volley缓存机制

版权声明:本文为博主原创文章,转载请注明出处。

相关文章推荐

探秘volley缓存网络数据

前言 众所周知,浏览器与服务器交互时可对响应的数据进行缓存,这极大的节省了用户的流量和提高了网站的响应性。对于app而言,理应做响应数据缓存。 实现方式 就我目前所知,主要是两种方式:以文件方式缓...

Volley在没有网的情况下使用磁盘缓存的数据

使用Volley的应该都知道,Volley中的缓存机制是基于http cache的,简单来说就是它的缓存是依赖于服务器的。但是一般没有网时我们打开app,还是会展示最近一次展示的内容,所以,需要对它进...

Android-Volley网络通信框架(二次封装数据请求和图片请求(包括处理请求队列和图片缓存))

1.回顾       上篇 使用 Volley 的 JsonObjectRequest 和 ImageLoader 写了 电影列表的例子 2.重点      (1)封装Volley 内部 请求 类  ...

Volley网络框架之缓存加载图片、Post与get的数据请求

前言:Volley作为主流网络框架之一,必然有它的优点。Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身, 它的常用在数据量不大,但网...

使用volley+universal image loader实现数据缓存和读取

什么是volley volley是谷歌于2013推出的一款网络访问框架。具体怎样使用可以参考csdn其他博客教程,这里不重复造轮子 volley隐藏特性 1.默认自带缓存,缓存路径在-----'...

android-volley 图片缓存分析与比较

关于android图片缓存开源框架,被程序猿们津津乐道的应该是,Volley , Universal-Image-Loader 和 picasso。关于他们大家问的最多的问题是,到底Volley和UI...

4、Volley解析(二),源码的深入分析一,缓存线程和网络请求线程

前言首先来看一下谷歌的官方流程图

volley获取图片并缓存

  • 2015-12-31 14:45
  • 2.62MB
  • 下载

Volley+瀑布流+缓存

  • 2013-10-24 13:38
  • 1.48MB
  • 下载

【进阶android】Volley源码分析——Volley的缓存

上一章我们重点分析了Volley框架之中两种线程的处理流程,以及这两种线程是如何与UI线程进行通信的。        本章我们将分析Volley框架之中的缓存机制。        任何一个网络请求都会...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)