Rainmaker
Rainmaker

Reputation: 11100

Cache of Original Image Is Not Reused When Applying Transform in Picasso

I am trying to switch between the original and transformed bitmaps using Picasso. The problem is the first time the original is loaded it seems to be cached, but when I load the transformed image then it seems to reload the image again and not using the cache. The same url is used to fetch the image. It happens only the first time for the original and transformed and then the cache is used.

My expectation that Picasso should automatically reuse the original image cashed to apply the transform and reload it with no delay. Maybe I am missing something.

Here is the code of image loading.

 private fun loadOriginalImage(i: Product, productImage: ImageView) {
    Picasso.get().load(getProductUrl(i.id)).placeholder(R.color.light_grey)
        .error(R.color.light_grey).fit().centerCrop().into(productImage)
}


 private fun loadGreyedImage(i: Product, productImage: ImageView) {
    Picasso.get().load(getProductUrl(i.id)).placeholder(R.color.light_grey)
        .error(R.color.light_grey).fit().centerCrop().transform(GrayScaleTransform()).into(productImage)
}

Picasso version implementation 'com.squareup.picasso:picasso:2.71828'

Upvotes: 2

Views: 530

Answers (2)

Rainmaker
Rainmaker

Reputation: 11100

After enabling logs I verified that the original image was cached indeed and as @Sputnik suggested the problem seemed to be caused by a delay in creating a transformed bitmap from the original image cache.

But the solution of pre-caching transformed images is not the best one imo. First of all, there is quite some images and greyscaled ones are required only when user clicks on the image in the recycler. It may never happen but we already cached double size of images just in case.

So after playing with Picasso and logs the solution that works for me was to use the original image as a placeholder.

so instead of

    Picasso.get().load(getProductUrl(i.id)).placeholder(R.color.light_grey)
    .error(R.color.light_grey).fit().centerCrop().transform(GrayScaleTransform()).into(productImage)

I did this

    Picasso.get().load(getProductUrl(i.id)).placeholder(productImage.drawable)
    .error(R.color.light_grey).fit().centerCrop().transform(GrayScaleTransform()).into(productImage)

This way my placeholder is the original image and it make the transition smooth and gets rid of potential overhead with caching all the transformed images.

Upvotes: 1

Sputnik
Sputnik

Reputation: 328

Was it memory cache or disk cache? How did you verify that the cache wasn't used indeed?

There are some options here(considering MemoryPolicy and NetworkPolicy were not modified and you didn't replace standard okHTTP3 client):

  • Image was pushed out of memory cache between these two calls(cache too small, invalidate call etc)
  • Disk cache is under control of HTTP client and has nothing to do with Picasso so improperly set up http headers could cause this(but in that case original image should be removed from the memory cache already)

Turning on indicators and logging can give more information on what's going on:

Picasso  
.with(context)
.setIndicatorsEnabled(true)
.setLoggingEnabled(true)

Also, if there's a possibility to do these two calls only, you can execute them and grab the snapshot data from the memory cache to check its size, hits and misses etc.:

StatsSnapshot stats = Picasso.with(context).getSnapshot();  
Log.d("stats", stats.toString());  

That possibly can give more debug information to consider e.g. were there exactly two calls to the cache or not, was there a miss etc

Edit: is key() function properly implemented in your transform?

Upvotes: 1

Related Questions