Picasso - keeping images on disk - android

I'm using Picasso to download images in my app. My understanding is that it uses a http client (HttpResponseCache or OkHttpClient) to cache these images on disk.
Without knowing much about either of these libraries, is it possible to mark certain images as permanent? In other words, I would like to download an image and guarantee that it will be available offline.
Thinking about it, I couldn't really have the disk cache go over a certain size, so I guess what I really need is to remove the TTL on the image url and allow the cache to remove images in a first in first out scenario.
In that case, can I control which image will be deleted first (by using a timestamp based on accessed, rather than downloaded)?
Update
Based on the answer from this SO question:
Android + Picasso: changing URL cache expiration
So this answers the first part of the question - we can control the TTL through the server.
After talking to a colleague, he pointed out that the http client should take into account how frequently an image is accessed (in addition to the TTL). So hopefully I don't have to worry about this either.
That leaves me with one question. I know which images I don't need anymore, can I remove an image from the disk cache?

You can iterate the elements in OkHttp's disk cache, and call Iterator.remove() to get rid of the ones you don't want.
http://square.github.io/okhttp/javadoc/com/squareup/okhttp/Cache.html#urls--

You'd have to extend Picasso's default cache and create a custom Picasso instance to use it:
Extend LruCache
Override the void set(String key, Bitmap bitmap) method to do what you describe (adding timestamp, etc.). Check out the original source code here.
Make sure that the original trimToSize method is never called by set (and clearKeyUri for that matter), and write your own to check for the timestamp etc to get the behavior you describe
Create a custom Picasso instance with your custom cache like this:
Picasso picasso = new Picasso.Builder(context).memoryCache(cache).build(); Picasso.setSingletonInstance(picasso);
Where cache is an instance of your custom LruCache class

when you want to store the images on the disk you should use the okhttpdownloader
OkHttpClient client = new OkHttpClient.Builder()
.cache(new Cache(getCacheDir(), Integer.MAX_VALUE))
.build();
Picasso build = new Picasso.Builder(this)
.downloader(new OkHttp3Downloader(client))
.build();
Picasso.setSingletonInstance(build);

Related

Clear glide cache across all activites?

I have the user's profile pic across multiple activities in my app. Once, they change their profile image, I want to make sure that all my Glide instance's cache are cleared. That way when they navigate around the app, they can see their updated profile pic.
Currently I'm using this method: Glide.get(activity).clearDiskCache(); and that only clears the Glide cache for that activity and not across my app.
Hope someone has a quick solution, where I don't need to call the .signature() function for each glide instance in each of my activites. Or clear each glide cache in each activity.
Try
Glide.get(context).clearMemory();
OR
Glide.get(context).clearDiskCache();
Note: clearMemory() must be called on the main thread. clearDiskCache() must be called on a background thread. You can't call both at once on the same thread.
I went through this whole windmill trying Signatures and clearing caches, and to be honest - none of those options work particularly well and they're usually slow.
Glide's first recommended solution is bar far superior, although it can sometimes take a bit more time to rework your code. I eventually lost my marbles and made the necessary changes to my code. It was well worth it.
Solution: Change the image name of the image when the user uploads a new image. Get the file name and use that. Once the image URL has changed, Glide understands you have changed the image and will update the Cache accordingly.

Picasso: Call fetch on same URL multiple times

I want to pre-fetch images using the Picasso library. In the documentation of Picasso I find the description for fetch
public void fetch():
Asynchronously fulfills the request without a ImageView or Target. This is useful when you want to warm up the cache with an image.
Note: It is safe to invoke this method from any thread.
For into(...) the behaviour is obviously that Picasso takes the image from the cache (if still available).
But what happens when I call fetch multiple times for the same image / url? Is the image re-fetched (from the network) or does Picasso find the image in the cache?

Prevent Picasso to fetch already loaded images and unable to use OkHttp2.0 for disk caching

Both of above is related. Following is my case
I am using Volley Library
Picasso(2.3.2) to load images
Images are fairly large,so I resize them to dimension 300x300
But during scroll of ListView/GridView, the images are reloaded again. Though the reload time is fairly small, I do not want the reloading of such nature.
So browsing, net I came across following
Use OkHttpClient caching mechanism
How to implement my own disk cache with picasso library - Android?
So I tried using OkHttp 2.0.0 into Volley Library
https://gist.github.com/JakeWharton/5616899
I think , from OkHttp 2.0.0 there is something to be changed on above gist.
So I followed this instead
How to implement Android Volley with OkHttp 2.0?
But the Volley library won't function now using method 2.
Finally, I am trying to use caching as mentioned on this
https://gist.github.com/ceram1/8254f7a68d81172c1669
So, my question is fairly simple, how not to reload the images that has been already downloaded. And if ,I have to use OkHttp 2.0.0 for disk caching, what are the ways, I should follow.
Stay with flow of how cache should work. Don't know Picasso cause I use Aquery, but they should use pretty much same flow whenever a bitmap(bm) needs to 'load' in some image view.
Flow:
If bm is thumb do chekthm
If bm large do cheklarge
On thmb:
If in memcache return bm for load to view
If in filecache return bm from there
In temp bm still null do network fetch to return bm
, with loads to respective caches and with 'ejects' 4 onFullCache.
For large bm , use same flow like thmb only config cache holds not as many entries.
Nowhere in there do you have to prevent a fetch . why because the process Only arrives at choice of network fetch when the bm Not avail from local options. At that point u either use default drawible from local res ( not correct bm for your logic) or you must do network fetch.

Get image uri from picasso?

I have a fairly large list of image URL's that I'm using to load up a ViewPager using Picasso. I need to be able to provide sharing capabilities for these images via an intent (ultimately sharing via ShareActionProvider). From what I've read, Picasso isn't really built to handle this sort of thing out of the box, though it provides all the necessary tools to do so.
My plan before research was to create a simple LruCache which uses the url as the key and bitmap value. This caching would occur in onBitmapLoaded via Picasso's Target interface. Whenever I want to share an image, I'll check the cache for the bitmap. If it's not there, I'll fetch with Picasso. Now that I have a cached bitmap regardless, I'll write to a file (...this part doesn't seem right, though I have to write to a file to get a uri, right?) and add the file uri to the intent.
However I see that with the Picasso.Builder I can set (and retain a reference to) my own cache - https://stackoverflow.com/a/18552559/413254. This means I could do away with the custom Target and confusion with properly implementing hashCode and equals methods to ensure accurate recycling, retrieval, etc.
My question is, how does Picasso use this cache? What are the keys? Is there a way to get a bitmap Uri without writing it to disk?
If you want to use ShareActionProvider to share the image on the current page you don't have to keep your own cache of images. But to be able to share it to others, the image should be in the shared file system on the device.
It would be better if you use image loading libraries with custom disk cache support like Universal Image Loader
If you want to use Picasso (which is a good decision).
You either have to save a copy of the image on every page change which is nor a good option.
Or you can give a custom network handler to Picasso and set a custom cache implementation to it. I would suggest using OkHttp with custom caching which stores files in the format you desire. When you do that, you have to have a function that converts image URLs to file path on a device.
In every page change, if you have a Fragment inside your ViewPager, put the ShareActionProvider into your Fragments.
Get the reference of the ShareActionProvider inside onCreateOptionsMenu. And then set the Intent with the file path you get.
Intent shareIntent = new Intent(Intent.ACTION_SEND);
Uri phototUri = Uri.parse(Utils.getFilePath(imageUrl));
shareIntent.setData(phototUri);
shareIntent.setType("image/png");
shareIntent.putExtra(Intent.EXTRA_STREAM, phototUri);
mShareActionProvider.setShareIntent(intent);
Edit:
The other option I would prefer is to ditch ShareActionProvider and use a normal menu item for this. The problem with ShareActionProvideris that you have to make the share Intent ready for user to share before hand. You have to make it ready even the user won't share it.
But when you have a normal button, it is much easier because you only make the operation when the user clicks the share button. In that case you can simply request the image one more time from Picasso with a Target object and write the Bitmap you got to a file in the shared external file system and share it.

When to Load image in ListView?

When I use ListView the getView() method is called many times. Every time when the getView() is called i load the image with Asyc task. I mean every time i reset the image which is annoying.
How to understand when to load the image?
You should cache loaded images, by storing i.e. on SD card, so once you got a copy there, no need to download it again. There's lot of ready-to-use classes that can do the job for you, like:
http://greendroid.cyrilmottier.com/reference/greendroid/widget/AsyncImageView.html
you must must have two flags.
One which says if you've already loaded the image, if true you do nothing.
One which says if you're currently loading the image, if true you do nothing.
The members will also help you on maintaining the state of the image.
Your code should look something like this:
private boolean isLoading = false;
private boolean hasLoaded = false;
if(!hasLoaded){
if(!isLoading){
isLoading = true;
//do async load
//on positive completition callback set hasLoaded to true
//on negative completition callback set isLoading to false
}
}
One of the best solution is to create image cache using the WeakReference. This way you can keep images in memory and only need load from server when they are not in memory. In this method the image would be removed from the memory when system encounter low memory situation. So your current activity would always keep the hard reference to the bitmap's required and the image cache would keep the weak reference to the bitmap's.
below reference links will help you
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
http://www.codeproject.com/Articles/35152/WeakReferences-as-a-Good-Caching-Mechanism
the Volley library (made by google) has a very intuitive class for an imageView that can have a url , called "NetworkImageView" .
you should check it out and watch the video, since they show that it's quite annoying to do it using asyncTask (plus the asyncTask is known to have a limit of tasks, about 255 or so) .
for setting the url, just use setImageUrl .
it has some useful methods for the phases of loading too: setDefaultImageResId , setErrorImageResId.
it's also supposed to have built in caching mechanism of some sort, but i haven't read much about it, so you might want to check out their samples.
this will remove the need to use asyncTasks for the listView's items.
one of my questions regarding the volley includes a sample code , here .
You can add a caching layer and optionally preloading the images. A good strategy for caching Images (Bitmap objects to be exact) is to use a strategy called LRU or least recently used.
Android support library has a class called LruCache that implements this strategy. So for example, when you download/load the image for the first time, you stick it into the cache. later, you can first check if it's already in cache and load it from there.
For preloading, A good rule of thumb is to preload the previous ten and the next ten items.

Categories

Resources