Picasso图像重新下载以适应具有不同尺寸的ImageView?

16

我在我的应用程序中使用Picasso来高效地加载图片,它正在以最佳方式工作。问题是,当前如果我多次使用相同的URL调用Picasso.with(),但每次都使用具有不同尺寸的ImageView,那么图像会再次下载。在Glide中,我们有.diskCacheStrategy()方法,其中包括DiskCacheStrategy.SOURCE以解决此问题。Picasso有没有其他替代方法?

这个查询中,我们将为Glide获得解决方案,但不适用于Picasso。如何在不重新下载图像的情况下重用它以供不同尺寸的ImageView使用。

这是我正在使用的代码

Picasso.with(context)
                .load(URI)
                .placeholder(R.drawable.ic_profile_thumb)
                .resize(180, 180).centerInside()
                .into(viewHolder.imgThumbnail);

请查看这个答案 https://dev59.com/rWEh5IYBdhLWcg3wyGDy#28964219。希望这能帮到你!! - Adarsh Yadav
你能贴一下与Picasso相关的代码吗?你是否使用了resize选项? - Sotti
@Scotti 请检查我的代码。我正在使用 resize 操作。 - Stella
@Stella:你有检查有问题的图片文件的HTTP头吗?如果它们不允许缓存,那么OkHttp或Volley可能会再次下载它-正如它们应该做的那样。 - david.mihola
4个回答

8
Picasso不会将图像缓存到磁盘上,它只有一个内存缓存。磁盘缓存是由网络库(OKhttp)完成的,因此写入磁盘缓存的图像永远不会被重新调整大小。
如果同一URL的图像被多次下载,则可能需要检查您的网络库。
如果您的项目使用okhttp库,则picasso将自动将其用作默认下载器。如果您使用其他任何网络库,则必须编写自己的下载器并将其设置为```downloader```。
Picasso.Builder(context).downloader(customDownloader)

这个链接 可能会让事情更加清晰明了


你能否用实际的代码解释一下你的答案?我正在使用Volley作为我的网络库。 - Stella
1
  • Picasso提供开箱即用的自动内存和磁盘缓存。请查看我上面的答案。
  • 据我所知,如果使用resize()方法,磁盘缓存中的图像将被调整大小。
- Sotti
@Sotti Picasso没有磁盘缓存。在这里检查jake的答案https://dev59.com/hWAg5IYBdhLWcg3wtMzD - null pointer
@billgates:嗯,自从两年前那个威胁以来,我不知道发生了什么。更近期的是这个(https://goo.gl/1V4Vps)或Picasso网页(http://square.github.io/picasso/),他们说Picasso提供“自动内存和磁盘缓存”。我不是说Http客户端没有参与,但无论使用哪个客户端(OkHttp、HttpUrlConnection……),看起来磁盘都以某种方式涉及其中,并且Picasso正在使用其Network.Policy属性。但在这一点上对我来说还不完全清楚。 - Sotti
@Sotti:你提供的第一个链接(Github问题)实际上证实了Picasso仍然依赖于OkHttp来进行任何磁盘缓存。正如Jake所确认的那样,增加磁盘缓存的正确/唯一方法是增加OkHttpDowloader的缓存大小,这反过来设置了Picasso的OkHttpClient的缓存大小。 - david.mihola

5

Picasso默认不会调整图片的大小。如果你简单地调用像下面这样的代码...

Picasso.with(context).load("https://goo.gl/v9EkbF").into(imageView);

...Picasso正在缓存完整大小的图像。从那一刻起,每次调用相同的URL,Picasso都将重用那个完整大小的图像,并让GPU将其调整大小到视图中。

如果使用resize()方法,则仅缓存调整大小的图像,如果您使用不同的大小,则Picasso需要重新下载该图像。

不要使用resize()选项,您将获得更好的带宽使用情况,但请注意内存使用情况。

Picasso的默认设置

Picasso确实具有自动内存和磁盘缓存。任何最近请求的图像都将在内存缓存中。如果那里没有,Picasso将检查磁盘缓存。如果磁盘上没有可用的图像,那么Picasso将开始网络请求。

所有请求的图像都会存储在两个缓存中,直到为了释放空间而必须删除它们为止。

2.5.2版本的默认值如下:

  • 15%可用应用程序RAM的LRU内存缓存
  • 2%存储空间,最多50MB但不少于5MB的磁盘缓存。
  • 如果包含在Gradle依赖项中,则Picasso将使用OkHttp作为Http客户端。否则,Picasso将退回到HttpUrlConnection。

您可以像这样增加磁盘缓存(例如100MB):

    Picasso picasso =  new Picasso
        .Builder(this)
        .downloader(new OkHttpDownloader(getCacheDir(), 100000000))
        .build();

    Picasso.setSingletonInstance(picasso);

更改磁盘缓存大小不会更改缓存策略。

内存策略

  • MemoryPolicy.NO_CACHE:该图像不会从内存中提供服务。这个选项不能避免从磁盘中提供图像。要避免磁盘查找,请参见网络策略
  • MemoryPolicy.NO_STORE:该图像不会存储在内存中。对于仅需加载一次的图像,请使用此选项。

示例

Picasso
        .with(context)
        .load(https://goo.gl/v9EkbF)
        .memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
        .into(imageView);

网络策略

  • NetworkPolicy.NO_CACHE:不会从磁盘缓存中提供图片。
  • NetworkPolicy.OFFLINE:如果可能的话,该图片将仅从缓存(内存或磁盘)中提供,但绝不从网络提供。

示例:

Picasso
        .with(context)
        .load(https://goo.gl/v9EkbF)
        .networkPolicy(NetworkPolicy.NO_CACHE)
        .into(imageView);

内存和缓存的考虑因素

  • Glide 默认使用 RGB565 并将调整大小后的图像缓存到内存中。
  • Picasso 默认使用 RGB888 并将完整尺寸的图像缓存到内存中,让 GPU 在绘制时进行实时调整大小。

RGB565 是 RGB888 的一半大小。使用 RGB565 和较小的图像会导致 Picasso 的内存占用量更高(可能是 Glide 的 3 倍/4 倍)。

这些只是默认设置。Glide 可以配置为使用 RGB888,Picasso 可以配置为使用 RGB565 并仅在内存中缓存调整大小后的图像,就像 Glide 一样。

在相同的设置下,内存占用量几乎相同。

带宽考虑因素

  • Glide 为每个尺寸缓存单独的文件。如果您加载同一图像的另一个尺寸,则会在调整大小和缓存之前再次下载。
  • Picasso 总是从缓存中获取完整尺寸的图像,然后让 GPU 将其调整大小以适应视图。

您可以要求 Glide 缓存所有内容,包括完整尺寸的图像和调整大小后的图像,但默认情况下 Glide 的带宽消耗更高。

注意

Picasso 2.6 即将推出,我不知道有什么不同/新功能。

来源


有关此事的任何参考资料吗?我在 https://github.com/square/picasso/blob/master/CHANGELOG.md 中找不到 Picasso 具有“自动内存和磁盘缓存”的信息。 - ʍѳђઽ૯ท
好的,很棒,它在所有项目下面,我没有看到 :) +1并感谢您提及它,我刚刚更新了答案。 - ʍѳђઽ૯ท
  1. Picasso没有磁盘缓存,而是委托给网络层处理。
  2. 即使调用resize()方法,磁盘缓存(网络层)中的图像也不会被重新调整大小。
- null pointer

3

更新:顺便说一下,之前的链接已经过时了,这里是最新版本的更改:

https://github.com/square/picasso/blob/master/CHANGELOG.md

正如@Sotti所说,Picasso具有自动内存和磁盘缓存,他们在介绍部分提到了这一点:(最后一部分)**

http://square.github.io/picasso/#introduction


在此查询中,我们将得到Glide但不会为Picasso解决方案。如何在不重新下载图像的情况下重复使用ImageView的不同尺寸

实际上,Picasso仅具有内存缓存,但您可能希望使用OkHttp来实现磁盘缓存。

请查看此链接:https://dev59.com/dXbZa4cB1Zd3GeqPDDI4#18552559,其中写道:

如果您指的是磁盘缓存,那么Picasso目前不支持它。这是因为磁盘层缓存是由HTTP层完成的,并且没有区别。

还要查看这个:https://corner.squareup.com/2013/05/picasso-one-dot-oh.html

Picasso自动利用内存和磁盘缓存(由HTTP客户端提供)加快位图加载速度。为开发人员启用显示彩色标记,指示图像源。

还有,请查看这个问题:如何在Android中使用picasso库实现自己的磁盘缓存?

请使用OkHttp将文件保存在自定义缓存目录中:

OkHttpClient okHttpClient = new OkHttpClient();
File customCacheDirectory = new File(Environment.getExternalStorageDirectory().getAbsoluteFile() + "/MyCache");
okHttpClient.setCache(new Cache(customCacheDirectory, Integer.MAX_VALUE));
OkHttpDownloader okHttpDownloader = new OkHttpDownloader(okHttpClient);
Picasso picasso = new Picasso.Builder(mainActivity).downloader(okHttpDownloader).build();
picasso.load(imageURL).into(viewHolder.image);

来源:https://dev59.com/HmMk5IYBdhLWcg3w0RGU#33276054

正如你所看到的,使用了setCache



1
我认为值得指出的是,OkHttp仍然只会在HTTP标头允许缓存时缓存图像-我曾经有过一个客户抱怨每天图像没有重新加载,然后图像文件具有类似于“过期时间:2017年1月1日00: 00: 00 GMT”的标头。 - david.mihola
@david.mihola - 嗯,顺便感谢分享经验。 - ʍѳђઽ૯ท
1
你提供的Square博客链接已经过时,是3年前版本1.0的内容。现在已经发布了版本2.5.2,并且版本2.6也即将推出。你可以在他们的网页上阅读到Picasso具有“自动内存和磁盘缓存”功能。(http://goo.gl/tpTc1) - Sotti

3
您可以使用同一供应商“SquareUp”的OkHttp这个答案向您展示如何详细操作。

那么,如果我在URL保持不变的情况下使用缓存图像,但是图像正在更新,那么我应该怎么做才能克服这个问题呢?我的意思是,在glide中,我们有signature()方法,那么在picasso中有什么替代方法吗? - Stella
无论您使用OkHttp(如果它包含在项目中,Picasso将在其后台使用)还是使用HttpUrlConnection(如果未包含OkHttp且未定义其他内容,则Picasso将作为备用),缓存策略必须被定义,并且可以通过Picasso进行定义而不需要深入了解。然而,主要问题/范围对我来说并不是很清楚,可能只是简单地没有使用resize()方法。 - Sotti

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