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

Android Retrofit懒加载API缓存问题:1小时后才获取新数据

解决Retrofit请求缓存过旧的问题

问题根源分析

你的代码存在几个导致缓存异常的问题:

  1. OkHttpClient未配置缓存目录:没有指定缓存存储位置和大小,但如果服务器返回Cache-Control: max-age=3600(1小时)的响应头,客户端会默认遵循该规则缓存数据。
  2. CacheInterceptor逻辑混乱:
    • 同时设置maxAge(60, TimeUnit.SECONDS)和noCache(),两个配置冲突,noCache会强制请求去服务器验证缓存,但最后又硬编码设置max-age=60的响应头,逻辑矛盾。
    • Log语句写在return之后,永远不会执行,无法调试缓存逻辑。
  3. OkHttpClient构建冗余:代码中额外创建了一个未使用的OkHttpClient实例,可能导致配置不生效。

修复方案

方案1:全局禁用缓存(适合需实时数据的场景)

如果所有接口都需要实时数据,直接在拦截器中强制禁用缓存:

1. 修改CacheInterceptor

class CacheInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request().newBuilder()
            // 强制跳过缓存,直接请求服务器
            .header("Cache-Control", "no-cache, no-store, must-revalidate")
            .header("Pragma", "no-cache")
            .header("Expires", "0")
            .build()
        return chain.proceed(request)
    }
}

2. 修正OkHttpClient配置

移除冗余的构建代码,确保使用配置好的实例:

val okHttpClient: OkHttpClient = OkHttpClient.Builder()
    .connectTimeout(6, TimeUnit.SECONDS)
    .writeTimeout(6, TimeUnit.SECONDS)
    .readTimeout(6, TimeUnit.SECONDS)
    .addInterceptor(CacheInterceptor()) // 用应用拦截器,确保所有请求生效
    .build()

private val retrofit by lazy {
    Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .client(okHttpClient)
        .build()
}

val api: SimpleApi by lazy {
    retrofit.create(SimpleApi::class.java)
}

方案2:按需控制缓存(部分接口缓存,部分实时)

通过给接口添加自定义头,区分缓存策略:

1. 修改CacheInterceptor

class CacheInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val customCacheHeader = request.header("Custom-Cache")
        
        val modifiedRequest = when (customCacheHeader) {
            "no-cache" -> {
                // 实时接口:禁用缓存
                request.newBuilder()
                    .header("Cache-Control", "no-cache, no-store, must-revalidate")
                    .removeHeader("Custom-Cache") // 移除自定义头,避免传到服务器
                    .build()
            }
            else -> {
                // 缓存接口:设置短有效期(如30秒)
                request.newBuilder()
                    .header("Cache-Control", "public, max-age=30")
                    .build()
            }
        }

        val response = chain.proceed(modifiedRequest)
        // 替换响应中的缓存头,统一规则
        return response.newBuilder()
            .removeHeader("Pragma")
            .removeHeader("Cache-Control")
            .header("Cache-Control", customCacheHeader ?: "public, max-age=30")
            .build()
    }
}

2. 在API接口中指定策略

interface SimpleApi {
    // 实时数据接口
    @Headers("Custom-Cache: no-cache")
    @GET("api/latest-data")
    suspend fun getLatestData(): Response<DataModel>
    
    // 允许缓存的接口
    @GET("api/cached-data")
    suspend fun getCachedData(): Response<DataModel>
}

方案3:配置缓存目录并控制缓存有效期

如果需要启用缓存但自定义有效期,必须先指定缓存存储位置:

// 在Application或初始化类中获取缓存目录
val cacheSize = 10 * 1024 * 1024 // 10MB缓存空间
val cache = Cache(context.cacheDir, cacheSize)

val okHttpClient: OkHttpClient = OkHttpClient.Builder()
    .connectTimeout(6, TimeUnit.SECONDS)
    .writeTimeout(6, TimeUnit.SECONDS)
    .readTimeout(6, TimeUnit.SECONDS)
    .cache(cache) // 添加缓存配置
    .addNetworkInterceptor { chain ->
        val response = chain.proceed(chain.request())
        // 设置响应缓存有效期为30秒
        val cacheControl = CacheControl.Builder()
            .maxAge(30, TimeUnit.SECONDS)
            .build()
        response.newBuilder()
            .header("Cache-Control", cacheControl.toString())
            .removeHeader("Pragma")
            .build()
    }
    .build()

关键注意点

  • 应用拦截器vs网络拦截器:addInterceptor会拦截所有请求(包括缓存命中的请求);addNetworkInterceptor仅拦截发往服务器的请求,按需选择。
  • 避免配置冲突:不要同时使用noCache和maxAge,二者互斥。
  • 调试验证:可以用Charles等工具查看请求/响应头,确认缓存规则是否生效。

内容的提问来源于stack exchange,提问作者John Chu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 15:33:12