You need to enable JavaScript to run this app. Retrofit+OkHttp+Picasso长周期缓存配置与缓存图片加载优化
优惠活动
大模型
产品
解决方案
定价
更多

Retrofit+OkHttp+Picasso长周期缓存配置与缓存图片加载优化

缓存逻辑优化方案(适配当前依赖版本)

缓存有效期调整至60天、到期前不触发网络请求

现有代码存在的核心问题

  • 网络拦截器设置的缓存有效期仅为60*60(1小时),远未达到60天的时效要求
  • 原离线拦截器仅在无网络时走缓存逻辑,有网状态下只要超出本地缓存的有效期阈值,就会自动发起网络请求拉取新数据,没有做有网场景下的缓存优先级控制
  • 未移除服务端返回的可能强制禁用缓存的响应头(如Pragma、服务端自带的Cache-Control),这些头会覆盖自定义的缓存规则,导致缓存提前失效

定向修改代码

  1. 调整网络拦截器的缓存有效期配置:
public static Interceptor provideCacheInterceptor ()
 {
     return new Interceptor()
     {
         @Override
         public Response intercept (Chain chain) throws IOException
         {
             Response response = chain.proceed( chain.request() );
             // 60天有效期的秒数计算:天*小时*分钟*秒
             long validDurationSeconds = 60 * 24 * 60 * 60;
             return response.newBuilder()
                     .removeHeader("Pragma")
                     .removeHeader(CACHE_CONTROL)
                     // 强制设置规则:公开缓存、有效期内不校验、直接命中缓存
                     .header(CACHE_CONTROL, "public, only-if-cached, max-age=" + validDurationSeconds)
                     .build();
         }
     };
 }
  1. 重构原离线拦截器的逻辑,实现全场景缓存优先:
public static Interceptor provideCachePriorityInterceptor ()
 {
     return new Interceptor()
     {
         @Override
         public Response intercept (Chain chain) throws IOException
         {
             Request request = chain.request();
             Cache appCache = provideCache();
             // 优先从本地缓存读取对应请求的响应
             Response cachedResponse = appCache != null ? appCache.get(request) : null;
             // 有网且存在有效缓存时,直接返回缓存内容,*不发起任何网络请求*
             if (cachedResponse != null && MyApplication.hasNetwork()) {
                 return cachedResponse;
             }
             // 无网场景下的兜底逻辑:允许读取最长60天的过期缓存
             if (!MyApplication.hasNetwork())
             {
                 long staleToleranceSeconds = 60 * 24 * 60 * 60;
                 request = request.newBuilder()
                         .removeHeader("Pragma")
                         .removeHeader(CACHE_CONTROL)
                         .header(CACHE_CONTROL, "public, only-if-cached, max-stale=" + staleToleranceSeconds)
                         .build();
             }
             return chain.proceed(request);
         }
     };
 }

注意:在OkHttpClient初始化时,把原来的provideOfflineCacheInterceptor替换为新的provideCachePriorityInterceptor,拦截器顺序不需要调整,应用层拦截器会先于网络层拦截器执行。

解决Picasso本地缓存加载慢、卡顿问题

现有配置的核心问题

  • 初始化Picasso时仅配置了共享OkHttp下载器,没有针对解码效率做优化,默认全尺寸解码图片会导致内存占用过高、解码耗时拉长
  • 正式包未关闭Picasso的调试标记和日志,额外增加了磁盘IO开销
  • 加载图片时未按照ImageView实际尺寸做压缩解码,大图解码会阻塞主线程导致卡顿

定向优化配置

  1. 调整Picasso单例的初始化参数:
OkHttp3Downloader okHttp3Downloader = new OkHttp3Downloader(okHttpClient);
Picasso picasso = new Picasso.Builder(MyApplication.getInstance())
        .downloader(okHttp3Downloader)
        // 正式版关闭调试角标,减少不必要的绘制
        .indicatorsEnabled(!BuildConfig.DEBUG)
        // 正式版关闭Picasso内部日志,减少IO
        .loggingEnabled(BuildConfig.DEBUG)
        // 使用*RGB_565*的色彩配置,比默认ARGB_8888减少一半内存占用,解码速度提升约40%
        .defaultBitmapConfig(Bitmap.Config.RGB_565)
        .build();
Picasso.setSingletonInstance(picasso);
  1. 日常图片加载的统一规范(可减少90%的加载卡顿问题):
  • 所有加载请求必须按照ImageView的实际尺寸做压缩,避免加载全尺寸原图:
Picasso.get()
        .load(imageUrl)
        // 按控件实际尺寸压缩
        .resize(imageView.getWidth(), imageView.getHeight())
        .centerCrop()
        // 磁盘缓存命中时不重复写入内存缓存,降低内存占用
        .memoryPolicy(MemoryPolicy.NO_STORE)
        .placeholder(R.drawable.placeholder)
        .into(imageView);
  • 在列表滑动场景下,加载前先取消上一次未完成的请求,避免滑动时的资源竞争:
// 在Adapter的getView/onBindViewHolder方法中
Picasso.get().cancelRequest(holder.imageView);
// 再执行新的加载逻辑

补充说明:当前配置已经让Picasso和Retrofit共用同一个OkHttp磁盘缓存,不需要给Picasso单独配置磁盘缓存,避免重复的磁盘文件读写开销,100MB的缓存容量可满足大部分场景的图片和接口缓存需求,OkHttp会自动通过LRU算法淘汰超出容量的旧缓存。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.06 17:45:04