从 Glide 库的缓存中删除图像

我在我的一个项目中使用了 Glide 来显示文件中的图像。

下面是我如何显示图片的代码:

Glide.with(DemoActivity.this)
.load(Uri.parse("file://" + imagePath))
.into(mImage);

此位置的图像(imagePath)不断变化。默认情况下,Glide 缓存它在 ImageView中显示的图像。正因为如此,Glide 在该位置显示了缓存中的第一个新图像。

如果我改变图像的位置 imagePath与其他一些图像有相同的名称,然后滑翔是显示第一个图像,而不是新的一个。

两个问题是:

  1. 有没有可能总是从文件而不是缓存的图像? 这样的问题将得到解决。

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

105586 次浏览

As explained in the section Caching and Cache Invalidation of the Glide wiki:

Because File names are hashed keys, there is no good way to simply delete all of the cached files on disk that correspond to a particular url or file path. The problem would be simpler if you were only ever allowed to load or cache the original image, but since Glide also caches thumbnails and provides various transformations, each of which will result in a new File in the cache, tracking down and deleting every cached version of an image is difficult.

In practice, the best way to invalidate a cache file is to change your >identifier when the content changes (url, uri, file path etc).

Since you can't change the file path, Glide offers the signature() API that allows you sets some additional data to be mixed in to the memory and disk cache keys allowing the caller more control over when cached data is invalidated.

If you want to reload every time the image from the disk, you can change your code like this:

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

This is how I solved this problem.

Method 1: When the URL changes whenever image changes

Glide.with(DemoActivity.this)
.load(Uri.parse("file://" + imagePath))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(mImage);

diskCacheStrategy() can be used to handle the disk cache and you can skip the memory cache using skipMemoryCache() method.

Method 2: When URL doesn't change, however, image changes

If your URL remains constant then you need to use Signature for image cache.

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

Glide signature() offers you the capability to mix additional data with the cache key.

  • You can use MediaStoreSignature if you are fetching content from media store. MediaStoreSignature allows you to mix the date modified time, mime type, and orientation of a media store item into the cache key. These three attributes reliably catch edits and updates allowing you to cache media store thumbs.
  • You may StringSignature as well for content saved as Files to mix the file date modified time.

To benefit from the cache provided by Glide and ensure that the correct image is shown everytime, you can use the signature() API.

All you have to do is to set as signature an information that relates to the image file. When you replace that file, the information changes too and Glide knows it must reload it, ignoring the cache.

A valid information could be a digest (for example SHA-1) calculated on the file contents.

Glide.with(context)
.load(inputFile)
.signature(new StringSignature(sha1(inputFile)))
.into(targetImageView);

Here I found the following implementation of sha1() function:

public static String sha1(final File file) throws NoSuchAlgorithmException, IOException {
final MessageDigest messageDigest = MessageDigest.getInstance("SHA1");


try (InputStream is = new BufferedInputStream(new FileInputStream(file)) {
final byte[] buffer = new byte[1024];
for (int read = 0; (read = is.read(buffer)) != -1;) {
messageDigest.update(buffer, 0, read);
}
}


// Convert the byte to hex format
try (Formatter formatter = new Formatter()) {
for (final byte b : messageDigest.digest()) {
formatter.format("%02x", b);
}
return formatter.toString();
}
}

This will remove cache memory which is stored by Glide.And it should be done in background otherwise it will throw exception

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

If you save images to the same known filename as a convention and want to invalidate the Glide cache only when the file has changed, using the file modification timestamp can work well.

I was using such a convention for avatar images which I was downloading to File objects outside Glide, and then using Glide just to efficiently resize and make them round, etc.

So I ended up using the StringSignature strategy with the value of the file's lastChanged timestamp as the signature. Here's what the fluent code for that looks like:

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

where avatarFile is my java.io.File object, of course.

There are two ways to handle Glide cache refresh,

Firstway: - Add below with glide implementation

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

Second way:

If you able to identify image changes then give your new file name in below,

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

or you want to load every time with latest images , use below

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

Hope this helps.

This worked for me

  //use  diskCacheStrategy(DiskCacheStrategy.NONE) after skipMemoryCache(true)
Glide.with(this)
.load(image)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(imageview);

I had troubles with setting signature using Glide version 4.* with Kotlin. After some time I ended up with this:

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

It's an extension function for ImageView, and it's used this way:

 imageView.loadUrl(url)

I Hope it will help someone

Had troubles with Glide 4.2.0, StringSignature was not resolved.

Looks like StringSignature is not available anymore and you have to use ObjectKey instead.

So code looks like

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

signature with GlideApp

    GlideApp.with(imageView)
.load(url)
.signature(new ObjectKey(System.currentTimeMillis()))
.placeholder(R.drawable.sky)
.error(R.drawable.sky)
.into(imageView);

For Glide 4.3.+ library you need to something like this to ,

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

In the latest versions we should use RequestOptions

RequestOptions Provides type independent options to customize loads with Glide in the latest versions of Glide.

Make a RequestOptions Object and use it when we are loading the image.

 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);

And finally Kotlin implementation (For Fragments):

Glide.with(activity)
.load(url)
.apply(RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true))
.into(myImageView)

This one worked for me!

Glide.with(DemoActivity.this)
.load(Uri.parse("file://" + imagePath))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(mImage);

I was using Glide to load a File, and here's what I ended up doing to make sure Glide's disk cache was invalidated every time my file changed (even though it had the same path):

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

Programmatically simply you can use:

 // must run on main thread
Glide.get(getApplicationContext()).clearMemory();


// must run in background thread
Glide.get(getApplicationContext()).clearDiskCache();

For More

1) First clear disk cache.

private class ClearGlideCacheAsyncTask extends AsyncTask<Void, Void, Boolean>{


private boolean result;


@Override
protected Boolean doInBackground(Void... params) {
try {
Glide.get(getContext()).clearDiskCache();
result = true;
}
catch (Exception e){
}
return result;
}


@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if(result)
Toast.makeText(getActivity(), "cache deleted", Toast.LENGTH_SHORT).show();
}
}

You can call from your ui with new ClearGlideCacheAsyncTask ().execute();

2) Clear memory cache

// This method must be called on the main thread.
Glide.get(context).clearMemory();

Source : https://bumptech.github.io/glide/doc/caching.html

I worked on this for days, and all the above-mentioned solutions are just slow as a sloth.

I know you've probably read this before and ignored it because you thought it would probably take a lot of work to change your code. But seriously, it's well worth it. The performance, as far as I can tell, beats all the other methods presented, it's Glide's recommended solution, AND you don't need to skip cache or create signatures so it keeps your code cleaner too.

FROM Glide:

In practice, the best way to invalidate a cache file is to change your identifier when the content changes (url, uri, file path etc) when possible. - https://bumptech.github.io/glide/doc/caching.html

SOLUTION: Change the name of the image when the user uploads a new image. Get the file name and use that for example. Once the image URL has changed, Glide understands you have changed the image and will update the Cache accordingly. This has by far given me the best performance.

WHEN USING:

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

It never caches the images and this really makes images load slowly. You'd think Signatures are better for performance, but to me they seemed just as slow.