Retrofit缓存实现

Posted by alonealice on 2016-10-09

之前在使用网络请求缓存时,一直使用的是手动的方式。手动获取返回的数据,手动存储,手动读取缓存。这种方式麻烦、低效而且容易出错。在项目中一直使用的是retrofit2库作为网络库,retrofit2库本身并不支持存储,但是由于retrofit2基于okhttp实现,可以使用okhttp实现网络缓存。

首先我们要添加缓存地址和缓存最大体积

1
2
3
File httpCacheDirectory = new File(getCacheDir(), "responses");
//设置缓存 10M
Cache cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);

其次我们要创建okhttpclient,并且添加拦截器和缓存代码

1
2
3
4
5
6
7
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.cache(cache).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.client(client)
.build();

在这里最重要的就是拦截器的内容。一般情况下,我们设置缓存的目的无非两种,一是在请求时都直接读取已缓存的数据,二是在有网络时直接连接网络,没有网络时读取缓存数据,而这两者的区别都需要在拦截器中设置。

一、直接读取缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Interceptor interceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
String cacheControl = request.cacheControl().toString();
if (TextUtils.isEmpty(cacheControl)) {
cacheControl = "public, max-age=60"; //60秒之内读缓存
}
return response.newBuilder()
.header("Cache-Control", cacheControl)
.removeHeader("Pragma")
.build();
}
};

其中读缓存的有效时间是60s,表示在60秒之内无论如何都会去取缓存。

二、有网时请求网络,无网络时读取缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Interceptor interceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
if(isNetworkAvailable()){
return response.newBuilder()
.header("Cache-Control", "public, max-age=" + 0)
.removeHeader("Pragma")
.build();
}else{
int maxStale = 60 * 60 * 24 * 30; //缓存的最大时间是30天
return response.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader("Pragma")
.build();
}
}
};

在30天之内没网络的情况下会读取缓存。