Search code examples
androidcachingamazon-s3picasso

Picasso cache issues with AMAZON S3


Has anyone been able to solve the caching issue when loading images from AWS S3 ?

I'm using OKHttpClient and all that Jazz - but it looks like the cacheControl or whatever is not checking changes in ETag and LAST_MODIFIED headers. It is always taking the cached version.

I init Picasso like so:

OkHttpClient client = new OkHttpClient();
Picasso.Builder builder = new Picasso.Builder(appContext).downloader(new OkHttpDownloader(client));
Picasso built = builder.build();
Picasso.setSingletonInstance(built);

And the response headers look like so:

D/OkHttpDownloader: x-amz-id-2: gWhBHQvzDw1RFDteg8uxvq02XfaB6SySgMgKMk45x2E6An245Bl0OjgYgKsHMxzkVm2nF4GPwRI=<br/>
D/OkHttpDownloader: x-amz-request-id: D80E5602FF3E6002
D/OkHttpDownloader: Date: Tue, 17 Nov 2015 14:46:02 GMT
D/OkHttpDownloader: Last-Modified: Sun, 01 Nov 2015 15:39:41 GMT
D/OkHttpDownloader: ETag: "2a082d4f2d42de95cc1b673a7742fec3"
D/OkHttpDownloader: Accept-Ranges: bytes
D/OkHttpDownloader: Content-Type: image/png
D/OkHttpDownloader: Content-Length: 798624
D/OkHttpDownloader: Server: AmazonS3
D/OkHttpDownloader: OkHttp-Selected-Protocol: http/1.1
D/OkHttpDownloader: OkHttp-Sent-Millis: 1447771561871
D/OkHttpDownloader: OkHttp-Received-Millis: 1447771562179

Edit:

Ok. After adding a cache control header on the put object request ("must-revalidate" was my weapon of choice) it partially solved the issue.

In order to force the running application to update a replaced image I had to accompany that with the following:

// Remove from memory cache
Picasso.with(appContext).invalidate(imageUrl);
// Remove from disc cache
Iterator<String> it = okHttpClient.getCache().urls();
while(it.hasNext()){
  String currentUrl = it.next();

  if(currentUrl.equals(imageUrl)){
    it.remove();                        
    break;
  }
}
// Update cache with new image
Picasso.with(appContext).load(imageUrl).fetch();

Solution

  • Expires: or Cache-Control: headers are notably absent from your response, which suggests that when you uploaded the files to S3, you didn't set them -- so you are at the whim of the viewer for caching behavior.

    Setting Cache-Control: max-age=3600 (or whatever lifetime you want) when you upload to S3 will result in these headers being returned with the object when it is downloaded. Or, you can go back, in the S3 console, and set them after you upload the object. You can also programmatically add them to already-uploaded objects by sending an API call to S3 to copy an object onto itself, with modified metadata.