如何缓存Web服务器返回的OkHTTP响应?实现RecyclerView数据缓存
解决OkHTTP缓存JSON数据实现RecyclerView数据离线复用的问题
嘿,我来帮你搞定这个缓存需求!从你贴出的请求响应头来看,目前服务器没有返回Cache-Control、ETag这类标准缓存相关的响应头,不过没关系,我们可以通过OkHTTP的缓存拦截器来实现「首次启动全量下载缓存,后续优先用缓存、避免重复请求」的逻辑,下面是具体实现方案:
一、基础配置:给OkHTTP设置缓存目录
首先得让OkHTTP有地方存储缓存数据,我们可以用应用的私有缓存目录:
// 获取应用专属缓存目录 File cacheDir = new File(context.getCacheDir(), "okhttp_json_cache"); // 设置缓存最大容量(这里设为10MB,可根据你的数据量调整) int cacheMaxSize = 10 * 1024 * 1024; // 10 MiB Cache okHttpCache = new Cache(cacheDir, cacheMaxSize);
二、核心:自定义缓存拦截器控制缓存策略
我们需要编写一个拦截器,区分「首次启动」和「非首次启动」的请求逻辑,同时给响应添加缓存有效期:
Interceptor jsonCacheInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); SharedPreferences prefs = context.getSharedPreferences("app_cache_prefs", Context.MODE_PRIVATE); boolean isFirstLaunch = prefs.getBoolean("is_first_launch", true); Request modifiedRequest; if (isFirstLaunch) { // 首次启动:强制请求网络,确保拿到全量数据 modifiedRequest = originalRequest.newBuilder() .cacheControl(CacheControl.FORCE_NETWORK) .build(); } else { // 非首次启动:优先使用缓存,缓存有效期设为7天(可根据需求调整) modifiedRequest = originalRequest.newBuilder() .cacheControl(new CacheControl.Builder() .maxAge(7, TimeUnit.DAYS) .build()) .build(); } // 执行请求,拿到响应 Response response = chain.proceed(modifiedRequest); // 给响应添加缓存头,让OkHTTP把这次响应缓存起来 return response.newBuilder() .header("Cache-Control", "public, max-age=604800") // 7天对应的秒数 .removeHeader("Pragma") // 移除旧的缓存控制头,避免冲突 .build(); } };
三、构建带缓存功能的OkHttpClient
把缓存和拦截器整合到OkHTTP客户端中:
OkHttpClient okHttpClient = new OkHttpClient.Builder() .cache(okHttpCache) .addInterceptor(jsonCacheInterceptor) // 应用拦截器,处理所有请求 .addNetworkInterceptor(jsonCacheInterceptor) // 网络拦截器,处理网络请求时的缓存验证 .build();
四、标记首次启动状态
首次启动完成后,记得标记为非首次,避免每次都强制请求网络:
// 在首次请求成功后执行 SharedPreferences.Editor editor = context.getSharedPreferences("app_cache_prefs", Context.MODE_PRIVATE).edit(); editor.putBoolean("is_first_launch", false); editor.apply();
额外优化建议(如果能协调后端的话)
如果可以让后端同事配合,建议在响应头中添加以下字段,让缓存逻辑更可靠:
Cache-Control: public, max-age=604800:直接告诉客户端缓存有效期ETag: xxx:服务器生成的资源唯一标识,后续请求带上If-None-Match: xxx,服务器返回304就说明数据没变化,直接用缓存Last-Modified: xxx:资源最后修改时间,后续请求带上If-Modified-Since: xxx,同样可以验证数据是否更新
这样客户端的缓存逻辑会更精准,不用完全依赖本地的有效期设置。
内容的提问来源于stack exchange,提问作者unipin
相关产品推荐
相关产品推荐

