关于Okhttp缓存

Okhttp的缓存策略有如下几种:

boolean noCache;//等于FORCE_NETWORK,不使用缓存
boolean noStore;//不缓存,不存储
int maxAgeSeconds = -1;//缓存的有效时间
int maxStaleSeconds = -1;//缓存的延长有效时间
int minFreshSeconds = -1;//增加额外的缓存的有效时间,在stale前计算
boolean onlyIfCached;//等于FORCE_CACHE,有缓存就用缓存
boolean noTransform;//不接受经过转码的响应
boolean immutable;//缓存有效时间内,响应不会变化,避免服务器处理304响应

如果这些缓存策略可以满足需求,那就不用再往下看了,相关的文章有很多

如果需要有网络用网络,无网络(网络请求失败)时使用缓存,或其他自定义策略,可以参考下面的方法

首先需要明确几个要求
1.使用拦截器来实现,改动小,作用全局
2.方便控制每个接口是否缓存
3.接口参数有改动时也能命中缓存

实现

一.存取

理想的情况下最好是将整个Response都存储起来,但是看一眼源代码

public final class Response implements Closeable

public interface Closeable extends AutoCloseable
 
public interface AutoCloseable

整个继承和实现的链条里跟序列化没有一毛钱关系,并且是不能被继承的final class
\color{red}{------所以,如果是在内存中临时缓存,可以保存整个Response,持久化保存就别想了}

那既然不能保存Response,是否可以自己组装一个,答案是肯定的

Response通过Builder方式创建,这个Builder也是public的可以调用到

public Builder() {
  headers = new Headers.Builder();
}

那组装时需要哪些参数呢,点一下试试

Response的参数们

emmm...有点多,以后再详细说明这些参数,先偷个懒,可以先看一下哪里用到了这个Builder


image.png

这里有okhttp自己实现的缓存拦截器,进去看看

return new Response.Builder()
    .request(chain.request())//原始请求,这个在拦截器中可以直接拿到
    .protocol(Protocol.HTTP_1_1)//协议,直接填就行
    .code(504)//code码,可以直接填200
    .message("Unsatisfiable Request (only-if-cached)")//可以随便写,我这里写得“use cache”便于以后统计
    .body(Util.EMPTY_RESPONSE)//数据内容*
    .sentRequestAtMillis(-1L)//请求时间
    .receivedResponseAtMillis(System.currentTimeMillis())//返回时间
    .build();

这里有一个现成的例子

上面代码中的*位置就是数据内容保存的地方,这里需要添加一个ResponseBody类型的参数,好在该类中有方便创建对象的方法

public static ResponseBody create(@Nullable MediaType contentType, String content)

这个方法有两个参数,第一个是内容类型,这个类中也有方便的方法

public static @Nullable MediaType parse(String string)//在一般返回的请求中直接使用MediaType.parse("application/json; charset=UTF-8")即可

第二个参数就是内容主体了,就是服务端返回的数据内容

构造Response现在已经清楚了,那现在就可以在保存缓存时只进行数据内容的保存即可,那应该如何保存呢

这里可以使用下面的代码获取到body中的数据并转为string类型

response.peekBody(Long.MAX_VALUE).string()

然后拿到这个数据可以用自己喜欢的方式进行持久化保存

简单使用可以用HashTable进行<Url,data>键值对保存,然后将其这个map整个写入到一个文件中,在使用时再整个读取出来,方便使用(或者使用xml,json等格式化数据),ps:为了安全起见只应该保存Get方法的数据,最好使用数据库进行持久化存储

这里需要注意如果使用HashMap可能会出现java.util.ConcurrentModificationException异常

二.根据接口选择是否缓存

这里的方法就很多了,说一个比较简单的

可以在请求时添加一个临时header,然后再拦截器中读取这个header进行辨认并将这个header删除(以免对请求产生不必要的影响)

如果使用retrofit进行网络请求,这种方式在Retrofit中使用多个baseUrl有详细说明

三.网络请求失败时命中缓存

这里只需要对拦截器中请求得部分进行try-catch即可,在网络请求失败时okhttp会抛错,这时再catch块中进行缓存的返回即可

需要注意的是下面的集中情况需要过滤,这是主动打断请求时会抛出的错误

e.toString().contains("Canceled")
e.toString().contains("InterruptedIOException")
e.toString().contains("CANCEL")

四.在请求参数改变时仍然命中(忽略某些参数)

这里需要对请求参数的改变有把握,比如net_type在使用移动网络的情况下应该可以命中wifi时缓存的数据

其实没啥可说的,将请求中的参数通过字符串分割的方式去掉其中的某些参数即可,需要注意的是保存和获取前的对比都需要去掉这些参数

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341