需求
- 有网络的情况下总是去访问服务器获取最新的数据,并把数据缓存到本地
- 无网络的情况下直接去缓存里找数据,如果没有找到就抛出异常 (提示:当前没有网络连接)
- 部分配置缓存的接口启用缓存
实现
- 主要就是用到了okhttp的拦截器,通过修改请求头的Cache-Control来实现缓存
- 关于okhttp的拦截器我们用到了两个方法addInterceptor和addNetworkInterceptor
addInterceptor和addNetworkInterceptor
addInterceptor优先addNetworkInterceptor执行 有网络的情况下addInterceptor和addNetworkInterceptor都会执行 没有网络的情况下addInterceptor执行,而addNetworkInterceptor不会执行 没有网络但是有缓存的情况下addInterceptor会执行,而addNetworkInterceptor不会执行
代码实现
public class CacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// 拦截请求头 判断哪些接口配置上了缓存(该配置是在retrofit上配置)
String cacheControl = request.cacheControl().toString();
// 如果没有配置过 那么就是走正常的访问,这里直接return回去了,并没有对请求做处理
if(TextUtils.isEmpty(cacheControl)) {
return chain.proceed(builder.build());
}
// 如果没有网络的情况下,并且配置了缓存,那么我们就设置强制读取缓存,没有读到就抛异常 503,但是并不会去服务器请求数据
if (!NetworkUtils.isConnected()) {
// 缓存一周
int offlineCacheTime = 60 * 60 * 24 * 7;
request = request.newBuilder()
// only-if-cached 强制使用缓存
// max-stale 即使这个缓存已经过期了,只要在max-stale这个时间内,还可以使用过期的缓存
.header("Cache-Control", "public, only-if-cached, max-stale=" + offlineCacheTime)
.build();
}
return chain.proceed(request);
}
}
// 跟平时retorfit写法一样,只是添加了@Headers这个配置
@Headers("Cache-Control:public, max-age=0")
@GET("user/account/getStudent/v1.0")
Observable<BaseResBean<UserBean>> getUserInfo(@QueryMap HashMap<String, Object> map);
public OkHttpClient provideOkHttpClient(Context context) {
// 先进行缓存目录的配置
File httpCacheDirectory = new File(context.getCacheDir(), "OkHttpCache");
// 设置缓存文件大小为10M
int cacheSize = 10 * 1024 * 1024;
Cache cache = new Cache(httpCacheDirectory, cacheSize);
OkHttpClient.Builder builder = new OkHttpClient.Builder()
...
// 缓存配置
.cache(cache)
// 启用缓存拦截器
.addInterceptor(new CacheInterceptor());
return builder.build();
}