从Glide库中清除缓存中的图像。

98
我在我的一个项目中使用Glide来显示文件中的图片。
以下是我展示图片的代码:
Glide.with(DemoActivity.this)
     .load(Uri.parse("file://" + imagePath))
     .into(mImage);

该位置的图像(imagePath)不断变化。默认情况下,Glide会将显示在ImageView中的图像缓存起来。因此,对于该位置的新图像,Glide会从缓存中显示第一张图像。

如果我将位于imagePath的图像更改为具有相同名称的其他图像,则Glide会显示第一张图像而不是新图像。

有两个查询:

  1. 是否可以始终从文件中获取图像而不是缓存?这样问题就会得到解决。

  2. 是否可以在获取新替换图像之前清除缓存中的图像?这也能解决问题。

19个回答

182
这是我解决这个问题的方法。
方法一:当图片改变时,URL也会改变。
Glide.with(DemoActivity.this)
    .load(Uri.parse("file://" + imagePath))
    .diskCacheStrategy(DiskCacheStrategy.NONE)
    .skipMemoryCache(true)
    .into(mImage);

diskCacheStrategy()可以用来处理磁盘缓存,而使用skipMemoryCache()方法可以跳过内存缓存。

方法2:当URL不变,但图片发生变化时

如果您的URL保持不变,则需要使用签名来进行图像缓存。

Glide.with(yourFragment)
     .load(yourFileDataModel)
     .signature(new StringSignature(yourVersionMetadata))
     .into(yourImageView);

Glide signature() 提供了将附加数据与缓存键混合的能力。

  • 如果您从媒体存储中获取内容,可以使用 MediaStoreSignatureMediaStoreSignature 允许您将媒体存储项的修改日期、MIME 类型和方向混合到缓存键中。这三个属性可靠地捕获编辑和更新,使您能够缓存媒体存储的缩略图。
  • 对于保存为文件的内容,您也可以使用 StringSignature 来混合文件的修改日期时间。

它对我有效。确保你实际上正在更改图片。 - Juan José Melero Gómez
25
请注意,在Glide v4中,“StringSignature”已被“ObjectKey”替换,请参阅Glide v4 Caching - SoftWyer
在这个方法中,如果我们有相同的URL但版本不同,当我们传递版本时,它会加载相关版本吗? - Ishan Fernando
3
你没有解决两个问题中的一个:“在获取新替换图片之前是否有可能清除缓存中的图片?这也将解决问题。” - Nick
1
虽然这种方法能够工作,但每次加载图像时速度非常缓慢。 - The Fluffy T Rex
在v4版本中,可以使用.signature(new ObjectKey(System.currentTimeMillis()))(请注意,StringSignature在此版本中不起作用)。 - tanni tanna

64

如Glide维基中的缓存和缓存无效部分所解释:

由于文件名是哈希键,因此没有简单的方法可以仅删除与特定URL或文件路径对应的所有缓存文件。如果您只允许加载或缓存原始图像,则问题会更简单,但是由于Glide还缓存缩略图并提供各种转换,每个转换都将在缓存中产生新文件,因此跟踪并删除每个缓存版本的图像是很困难的。

实际上,在内容更改(url、uri、文件路径等)时使您的标识符发生变化是使缓存文件失效的最佳方法。

由于您无法更改文件路径,因此Glide提供了signature() API,允许您设置一些额外的数据以混合到内存和磁盘缓存键中,从而使调用方更多地控制缓存数据何时失效。

如果您想每次都从磁盘重新加载图像,则可以按以下方式更改代码:

Glide.with(DemoActivity.this)
     .load(Uri.parse("file://" + imagePath))
     .signature(new StringSignature(String.valueOf(System.currentTimeMillis())))
     .into(mImage);

这正符合我的需求。我有一个适用于我的数据版本,因此只需添加 .signature(new StringSignature(Integer.toString(data.getVersion()))) 就可以在版本更改时强制更新图像。 - Krøllebølle
@Mattia Maestrini 谢谢,您的解决方案通过 System.currentTimeMillis() 将单张图片更新到缓存中? - DolDurma
1
所以我猜测这不会污染缓存目录,因为URL被隐含为常量,是吗?这意味着它将覆盖先前的缓存条目? - TheRealChx101
3
对于Kotlin的使用,使用.signature(ObjectKey(System.currentTimeMillis())) - Yonko Kilasi
使用 Glide 4.2.0 版本时,StringSignature 未被解析,因此请改用 ObjectKey - Dinesh

47

处理 Glide 缓存刷新有两种方式,

第一种方式: - 将以下内容添加到 Glide 实现中

.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)

第二种方法:

如果您能够识别图像变化,请在下面给出您的新文件名。

.signature(new StringSignature(String.valueOf(fileName)))

或者您想要每次加载时都使用最新的图像,请使用以下方法

.signature(new StringSignature(String.valueOf(System.currentTimeMillis())))

希望这可以帮到您。


40

这将删除 Glide 存储的缓存内存。应该在后台执行,否则会抛出异常。

new Thread(new Runnable() {
          @Override
          public void run() {
             Glide.get(MainActivity.this).clearDiskCache();
          }
     }).start();

1
那么系统如何决定在删除缓存后立即停止运行的线程呢? - Yash Agrawal
1
@YashAgrawal:这将由内部结构决定。所以不需要担心它。 - Anand Savjani
@AnandSavjani 你什么时候需要调用这个函数? - abh22ishek
@abh22ishek 当你想要在滚动RecyclerView或ViewPager时刷新图像,或者每当你需要使用相同的URL和相同的图像名称更新图像时。 - Anand Savjani

27

使用Glide 4.2.0遇到问题,StringSignature未能解决。

看起来StringSignature不再可用,必须改用ObjectKey

因此,代码如下:

Glide.with(imageView).
load(pathToImage).
apply(new RequestOptions().signature(new ObjectKey("signature string"))).
into(imageView);

16

如果您按照惯例将图像保存为相同的已知文件名,并且只想在文件更改时使Glide缓存无效,则可以使用文件修改时间戳。

我正在为头像图像使用这样的约定,我在 Glide 之外的 File 对象中下载它们,然后使用 Glide 只是为了高效地调整大小和制作圆形等操作。

因此,我最终使用了 StringSignature 策略,并使用文件的 lastChanged 时间戳作为签名值。下面是该策略的流畅代码:

Glide.with(this)
        .load(avatarFile)
        .diskCacheStrategy(DiskCacheStrategy.RESULT)
        .signature(new StringSignature(String.valueOf(avatarFile.lastModified())))
        .into(ivProfile);
}

其中 avatarFile 是我的 java.io.File 对象,当然了。


14

我在使用Kotlin和Glide 4.*版本时,设置签名遇到了麻烦。

经过一段时间的摸索,我最终得到了这个解决方案:

fun ImageView.loadUrl(url: String) {
    var requestOptions = RequestOptions()
    requestOptions.signature(ObjectKey(System.currentTimeMillis()))
    Glide.with(this).load(url).apply(requestOptions).into(this)
}

这是一个ImageView的扩展函数,使用方式如下:

 imageView.loadUrl(url)

我希望它能帮助到某人


1
exactly what I need. - Anton Derevyanko

13

对于 Glide 4.3.+ 库,你需要做类似这样的事情来:

Glide.with(context)
    .load(image_path)
    .apply(new RequestOptions()
                        .diskCacheStrategy(DiskCacheStrategy.NONE)
                        .skipMemoryCache(true))
    .into(imge_view);

13
在最新的版本中,我们应该使用RequestOptions。 RequestOptions提供了类型无关的选项,用于在Glide的最新版本中自定义加载。
当加载图像时,创建一个RequestOptions对象并使用它。
 RequestOptions requestOptions = new RequestOptions()
                        .diskCacheStrategy(DiskCacheStrategy.NONE) // because file name is always same
                        .skipMemoryCache(true);

 Glide.with(this)
           .load(photoUrl)
           .apply(requestOptions)
           .into(profile_image);

7

我使用Glide来加载一个File,以下是我最终采取的措施,以确保每次文件更改(即使具有相同的路径)时,Glide的磁盘缓存都被清除:

Glide.with(context)
    .load(bitmapFile)
    .signature(new ObjectKey(bitmapFile.lastModified()))
    .into(imageView);

1
非常聪明!这实际上是处理本地文件的最佳方式。感谢分享! - Jona

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接