You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何缓存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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:58:58