使Picasso缓存失效

77
我使用Picasso从磁盘加载图像,例如:Picasso.with(ctx).load(new File("/path/to/image")).into(imageView),但是当我在该文件中保存新图像并刷新我的ImageView时,Picasso仍然缓存了位图。
是否可以使Picasso的缓存失效?

1
在执行完Picasso.with(getActivity()).invalidate(file);之后,我该如何重新缓存呢? - tux-world
14个回答

86

实际上,根据您自己的答案,有一种更容易的方法来完成这项任务,而不需要复制该库。将此类添加到com.squareup.picasso包中即可。

package com.squareup.picasso;

public class PicassoTools {

    public static void clearCache (Picasso p) {
        p.cache.clear();
    }
}

由于缓存具有包可见性,因此此实用程序类可以帮助您清除缓存。您只需调用它:

因为缓存的可见范围是包,所以这个工具类可以帮你清空缓存。你只需要调用它:

PicassoTools.clearCache(Picasso.with(context));

21
不必访问 jar 包,你需要创建这个文件并将其放在正确的包中(com.squareup.picasso)。 - shalafi
4
如果你正在使用Android Studio的Gradle而不是附带的jar文件,有没有一种方法可以做到这一点? - TheLettuceMaster
3
不,你不需要触碰毕加索罐子,你只需要在正确的包中创建文件。 - shalafi
7
很遗憾,“Picasso.with(getApplication()).cache.clear();”无法起作用,如果能实现就会更加干净。 - Michael Schmidt
3
Picasso.cache 字段不可见! - Iman Marashi
显示剩余5条评论

86

最近的Picasso版本中,有一种新的无需任何解决方法即可使图像无效的方法。因此,在这种情况下,我认为之前提到的自定义PicassoTools类现在已经过时了。

Picasso.with(getActivity()).invalidate(file);

3
好的,那个确实使一个文件失效。目前还没有一种方法可以使所有缓存都失效。不过,我将近一年前就回复过这个问题了,所以他们现在加上了我并不感到惊讶。 - shalafi
8
无效化操作不起作用,图像仍然保留在磁盘缓存中。 - user5155835
8
由于invalidate()无法清除网络缓存,因此您需要使用Picasso.with(imageView.getContext()).load(imageUrl).networkPolicy(NetworkPolicy.NO_CACHE).into(imageView);来加载图像。 - Joe Maher
@mes .invalidate(url) 在重新获取URL图片后是否可以缓存? - tux-world
@shalafi,字段“cache”不再是公共的。 - usernotnull
显示剩余5条评论

66

通过以下代码片段使用标志emoryPolicy.NO_CACHE和NetworkPolicy.NO_CACHE指示内存策略,以中止内存缓存和磁盘缓存检查:

emoryPolicy.NO_CACHE 和 NetworkPolicy.NO_CACHE
   mPicasso.with(mContext)
            .load(url)
            .memoryPolicy(MemoryPolicy.NO_CACHE )
            .networkPolicy(NetworkPolicy.NO_CACHE)
            .resize(512, 512)
            .error(R.drawable.login)
            .noFade()
            .into(imageView);

1
谢谢!添加 .networkPolicy(NetworkPolicy.NO_CACHE) 对我很有帮助。 - Can Uludağ
1
通过这个答案图片永远不会被缓存!那为什么要使用它呢? - Iman Marashi
9
如果您通常使用相同的网址但不同的图像值(例如:amazonws.com/yourProject/user_profile_images/user1/profile.jpg),那么这很有用。该网址从不更改,但其值会更改。 - Borja

15

尝试使用:

Picasso.with(ctx).load(new File("/path/to/image")).skipMemoryCache().into(imageView)

这个可行,但是如果我们知道图片过期了,我想将图像“存储”到缓存中,而不是从缓存中读取。我发现在Picasso中无法直接实现这一点,所以我会将您的答案标记为正确的。 - Maarten
我想刷新之前加载的图像。skipMemoryCache() 做到了!谢谢! - joninx
这已经被弃用了。 - Rob

14

Picasso中搜索图像的顺序为:

内存缓存 -> 磁盘缓存 -> 网络

因此,我们需要在几种情况下使Picasso的缓存失效:

1. 失效内存缓存:

  • 使用场景:当磁盘缓存或远程主机中的图像已经更新时
  • 解决方案:如果存在Url、File或Uri的缓存,则清除缓存

mPicasso.with(appContext).invalidate(File);
mPicasso.with(appContext).invalidate(Url);
mPicasso.with(appContext).invalidate(Uri);

.

2.清除内存缓存和磁盘缓存 在线更新

※注意:在线更新指的是直接更新到 ImageView 上。

  • 用户案例:远程主机上的图像已更新

  • 解决方案:中止内存缓存和磁盘缓存中的图片,然后从远程主机请求图片。

mPicasso.with(appContext)
    .load(url)
    .memoryPolicy(MemoryPolicy.NO_CACHE )
    .networkPolicy(NetworkPolicy.NO_CACHE)
    .into(imageView);
  • 放弃内存缓存和磁盘缓存

  • .

    3.使内存缓存和磁盘缓存失效 离线操作

    ※ 注意:离线操作指的是更新后并不会直接显示在ImageView中,只是后台获取以备将来使用

    • 用户场景:您知道远程主机上的图像已更新,但只想更新缓存以供以后使用(而不是更新到ImageView中)
    • 解决方案:仅获取

     mPicasso.with(appContext)
        .load(url)
        .memoryPolicy(MemoryPolicy.NO_CACHE)
        .networkPolicy(NetworkPolicy.NO_CACHE)
        .fetch();
    

    ※注意:使用fetch()虽然效果好,但它也会消耗网络资源,请仔细考虑,并在下面的场景4中查看更好的解决方案。

    4.使内存缓存和磁盘缓存失效离线 如果磁盘缓存已存在

    • 用户情况:只有在磁盘缓存中已经存在时才可以使缓存失效
    • 解决方案:在获取之前使用参数NetworkPolicy.OFFLINE cache检查磁盘

     mPicasso.with(appContext)
        .load(url)
        .memoryPolicy(MemoryPolicy.NO_CACHE)
        .networkPolicy(NetworkPolicy.OFFLINE)
        .fetch(new Callback() {
            @Override
            public void onSuccess() {
                //Success: mean disk cache exist -> should do actual fetch
                picasso.load(url).fetch();
            }
    
            @Override
            public void onError() {
            //Failed: mean disk cache not exist
        }
    });
    

    Picasso是一个非常棒的库,希望Squareup在未来的更新中添加更多方便的API来管理缓存。


    12

    如果您想一次性删除所有缓存,可以创建一个自定义的Picasso.LruCache,然后使用clear方法清除它。

    以下是示例:

    Picasso.Builder builder = new Picasso.Builder(this);
    LruCache picassoCache = new LruCache(this);
    builder.memoryCache(picassoCache);
    Picasso.setSingletonInstance(builder.build());
    
    清除缓存:

    要清除缓存:

    picassoCache.clear();
    

    Picasso库的相同建议:https://github.com/square/picasso/issues/935 - vmeyer

    12

    另一种选择是删除缓存目录本身,例如在应用程序启动时:

    deleteDirectoryTree(context.getCacheDir());
    

    其中:

    /**
     * Deletes a directory tree recursively.
     */
    public static void deleteDirectoryTree(File fileOrDirectory) {
        if (fileOrDirectory.isDirectory()) {
            for (File child : fileOrDirectory.listFiles()) {
                deleteDirectoryTree(child);
            }
        }
    
        fileOrDirectory.delete();
    }
    

    这将删除整个缓存目录,如果您想模拟应用程序的首次使用,则没问题。如果您只想删除Picasso缓存,请将“picasso-cache”添加到路径中。


    @Lawrence Kesteloot,你能帮我解决这个问题吗?http://stackoverflow.com/questions/33657619/android-error-onbackpressed-with-deletedirectorytree-method。我之前已经成功使用了你的方法,但现在遇到了问题。提前感谢您的帮助。 - madsongr
    1
    其他答案只是清除了内存缓存,但没有清除磁盘缓存 - 这个方法也可以处理磁盘缓存! :) - Mohit Singh

    9
    您可以通过设置自己的缓存并清除该缓存来清除Picasso的图像缓存。 这段代码已在Picasso 2.5.0上进行了测试。
    private Picasso picasso;
    private LruCache picassoLruCache;
    
    picassoLruCache = new LruCache(context);
    
    // Set cache
    picasso = new Picasso.Builder(context) //
            .memoryCache(picassoLruCache) //
            .build();
    
    // Clear cache
    picassoLruCache.clear();
    

    6

    虽然循环不太美观,但这种方法解决了我在缓存和Picasso方面遇到的问题。仅在您想要使特定URL的缓存失效时使用此方法,此方法速度较慢,可能不是正确的操作方式,但对我有效。

        String url = "http://www.blablabla.com/Raiders.jpg";
        Picasso.with(this).invalidate(url);
        Picasso.with(this)
                .load(url)
                .networkPolicy(
                        NetworkUtils.isConnected(this) ?
                                NetworkPolicy.NO_CACHE : NetworkPolicy.OFFLINE)
                .resize(200, 200)
                .centerCrop()
                .placeholder(R.mipmap.ic_avatar)
                .error(R.mipmap.ic_avatar)
                .into(imageView);
    

    2
    这里的被接受答案缺少了一个非常重要的部分。我从这里找到了技巧:http://blogs.candoerz.com/question/124660/android-image-cache-is-not-clearing-in-picasso.aspx 当您使用自定义选项(如调整大小、中心裁剪等)显示原始图像时,只调用以下行不会清除照片的缓存。
    Picasso.with(getContext()).invalidate(file);
    

    解决方案:
    在显示图片时,使用stableKey()方法。
    Picasso.with(getContext()).load(new File(fileUri))
                             .skipMemoryCache()
                             .placeholder(R.drawable.placeholder)
                             .stableKey(fileUri)
                             .into(imageview);
    

    然后,您可以通过调用以下内容来清除此文件的缓存:

    Picasso.with(getContext()).invalidate(fileUri);
    

    希望这能有所帮助。

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