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

Glide 4如何对比远程与本地文件的Last-Modified请求头?

最优实现Glide 4对比远程与本地缓存Last-Modified的方案

在Glide 4中,不推荐像UniversalImageLoader那样手动操作缓存文件(因为Glide的缓存结构是经过哈希处理的,直接查找或删除缓存容易破坏Glide的缓存逻辑),更符合Glide设计的最优方式是利用Signature(签名)机制来关联远程文件的Last-Modified时间,让Glide自动判断是否需要更新缓存。下面分步骤给你详细实现方案:

1. 核心思路:用Last-Modified作为Glide的Signature

Glide的缓存键由请求模型(比如图片URL)和Signature共同决定。当远程文件的Last-Modified更新时,我们同步更新Signature,Glide就会认为这是一个新资源,自动重新下载并替换旧缓存,旧缓存会被Glide的LRU策略自动清理,无需手动删除。

2. 具体代码实现

第一步:封装获取远程Last-Modified的方法

和你之前UIL的逻辑类似,通过HEAD请求获取远程文件的Last-Modified时间:

private long getRemoteLastModified(String imageUrl) {
    HttpURLConnection connection = null;
    try {
        URL url = new URL(imageUrl);
        connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("HEAD");
        connection.setConnectTimeout(5000);
        connection.setReadTimeout(5000);
        connection.connect();
        return connection.getLastModified();
    } catch (IOException e) {
        e.printStackTrace();
        return 0; // 出错时返回0,后续会用默认缓存逻辑
    } finally {
        if (connection != null) {
            connection.disconnect();
        }
    }
}

第二步:加载图片时绑定Signature

获取远程Last-Modified后,用ObjectKey(Glide提供的通用Signature实现)创建签名,然后传入Glide请求:

// 获取远程文件的Last-Modified时间
long remoteLastModified = getRemoteLastModified(iconUrl);

// 加载图片,绑定Signature
Glide.with(context)
     .load(iconUrl)
     // 用远程Last-Modified作为签名,时间变化则缓存失效
     .signature(new ObjectKey(remoteLastModified))
     .listener(new RequestListener<Drawable>() {
         @Override
         public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
             // 处理加载失败逻辑,比如显示占位图
             return false; // 返回false让Glide继续处理默认失败逻辑
         }

         @Override
         public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
             // 当资源从远程下载时,说明缓存已更新
             if (dataSource == DataSource.REMOTE) {
                 Log.d(Appspress.LOG_TAG_DEBUG, "old picture detected. Redownloaded new version.");
             }
             return false; // 返回false让Glide继续处理资源显示
         }
     })
     .into(imageView);

3. 性能优化:缓存远程Last-Modified时间

上面的方案每次加载都要发HEAD请求,可能会增加网络开销。你可以把远程Last-Modified时间缓存到本地(比如SharedPreferences),设置一个过期时间(比如10分钟),过期后再重新请求:

private static final long LAST_MODIFIED_CACHE_DURATION = 10 * 60 * 1000; // 10分钟

private long getCachedRemoteLastModified(String imageUrl) {
    SharedPreferences sp = context.getSharedPreferences("ImageLastModified", Context.MODE_PRIVATE);
    long cachedTime = sp.getLong(imageUrl, 0);
    long cacheTimestamp = sp.getLong(imageUrl + "_timestamp", 0);
    
    // 如果缓存未过期,返回缓存的时间
    if (System.currentTimeMillis() - cacheTimestamp < LAST_MODIFIED_CACHE_DURATION) {
        return cachedTime;
    }
    
    // 缓存过期,重新获取并更新缓存
    long newTime = getRemoteLastModified(imageUrl);
    sp.edit()
      .putLong(imageUrl, newTime)
      .putLong(imageUrl + "_timestamp", System.currentTimeMillis())
      .apply();
    return newTime;
}

然后加载时替换为getCachedRemoteLastModified(iconUrl)即可。

4. 进阶优化:结合OkHttp自动处理缓存验证

如果你使用OkHttp作为Glide的网络库,可以配置拦截器自动发送If-Modified-Since请求头,让服务器判断是否需要返回新资源(返回304则复用本地缓存),这样无需提前发HEAD请求,更高效:

第一步:添加OkHttp集成依赖

在build.gradle中添加:

implementation 'com.github.bumptech.glide:okhttp3-integration:4.15.1'

第二步:配置OkHttp拦截器

OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request originalRequest = chain.request();
                String imageUrl = originalRequest.url().toString();
                
                // 从SharedPreferences获取本地缓存的Last-Modified
                SharedPreferences sp = context.getSharedPreferences("ImageLastModified", Context.MODE_PRIVATE);
                long localLastModified = sp.getLong(imageUrl, 0);
                
                // 添加If-Modified-Since请求头
                Request modifiedRequest = originalRequest.newBuilder()
                        .header("If-Modified-Since", new Date(localLastModified).toString())
                        .build();
                
                Response response = chain.proceed(modifiedRequest);
                
                // 如果返回200,说明资源更新了,保存新的Last-Modified
                if (response.code() == HttpURLConnection.HTTP_OK) {
                    Date lastModifiedDate = response.headers().getDate("Last-Modified");
                    if (lastModifiedDate != null) {
                        sp.edit()
                          .putLong(imageUrl, lastModifiedDate.getTime())
                          .apply();
                    }
                }
                return response;
            }
        })
        .build();

第三步:让Glide使用自定义OkHttpClient

// 替换Glide默认的网络加载器为OkHttp
GlideUrlLoader.Factory factory = new GlideUrlLoader.Factory(okHttpClient);
Glide.get(context).getRegistry().replace(GlideUrl.class, InputStream.class, factory);

这种方式下,Glide会自动处理缓存验证,无需手动设置Signature,服务器返回304时直接复用本地缓存,返回200时自动更新缓存和本地存储的Last-Modified。

总结

  • 最推荐的基础方案是使用Signature关联远程Last-Modified,无需手动操作缓存,符合Glide的设计规范。
  • 性能优化可以加上本地缓存Last-Modified时间,减少HEAD请求次数。
  • 进阶方案结合OkHttp拦截器,实现自动缓存验证,进一步节省带宽和提升加载效率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:53:20