Best practice for managing most used cached images - android

In the spirit of not reinventing the bicycle I'm wondering if there's an Android best practice approach (which I'm not finding through google, but I'm probably not articulating my search correctly) for keeping a defined amount of local storage allocated for downloaded bitmaps, which are kept around based on a most commonly utilized (rather than FILO or FIFO) algorithm.
So, what I'm going to be doing is grabbing an image if it's not already on the disk and storing it and marking it as "most recently needed". The next time it's used I'll be marking it as most recently needed again. Every time I do this I go through all the images and any image that has fallen beyond some threshold of recent utility will be deleted.
My algorithm also takes into account the reality that not all images are created equal and that there's a finite amount of space that I wish to allocate for image storage.
I'm not asking for "how to do this" (because I know how to do it)... I'm asking if there's already a prescribed approach that I should follow before I embark on my own custom implementation.

I think you need LruCahe. you can use UIL and all available caching mechanism or create your own with DiskLruCache. I think most of the libraries use LRU as an algorithm for caching images and I do not think any of them use LIFO or FIFO.

I can recommend the Picasso library for Android. Features as per site:
Handling ImageView recycling and download cancelation in an adapter.
Complex image transformations with minimal memory use. Automatic
memory and disk caching.
I'm not 100% sure if this meets your requirements but it's worth to take a look at.

Related

How do Image Loading Libraries like Coil or Glide do memory management?

I am new to Android development. My app has use case where I want to download and display images from Internet. I am using Kotlin to build App and decided to use Coil library as Image loading library. While using my application, user's action my trigger download of multiple images. How do these image loading libraries make sure that memory/cache/disk space doesn't fill up? Do these libraries clear/delete images that were downloaded during last use?
The answer is going to depend on the particular library. But in general, they download the images to a file, to serve as a disk cache. That disk cache generally is kept to some limit in terms of size, with files being deleted on an LRU (least recently used) basis. They may then do the same with in memory representations, keeping the last N megabytes worth of images cached in a pool, ejecting on an LRU basis when needed. Ejecting them from the cache may or may not remove them from memory entirely- it depends on if any other reference to the object is maintained by client code. Some libraries allow configurable behavior on this, by either allowing client code to set size limits or provide entire cache implementations.
It's still possible for space to fill up. Especially memory- if you have too many bitmaps open and use up all available heap, then you're going OOM no matter what the loading library does. What the loading library will do is prevent multiple network requests for the same image, and prevent you from having to do all the cache management by hand.

When should a photo be cached

Is there a general guideline or rule of thumb on when I should cache a photo?
For example I have a grid view of smaller icon images. This page isn't at the beginning of the app so there's no guarantee a user sees it, these images could change server-side but for the most part they won't. Should I cache them because there are so many or not worry about them because they are small?
Another example would be if I click on one of the images mentioned above it will lead me to a view with one larger image, should I cache this image since it's larger or should I let the user make a network request each time?
I'm not looking for an answer for these specific questions, but rather a guideline to follow.
To clarify by caching I mean saving the file to storage. Also, is there a better method than this?
Thanks for the help!
Caching is an important feature in user experience, so even if there's no guarantee the user sees that particular 'page', it a nice thing to have.
Saving images in a cache depends directly on many variables:
- How much time does it take to regenerate images if not cached
- How many images are we talking about
- How often do they change
- What size is each image
For example, having 100 thumbnails of images that change every month makes a lot of sense. Caching 200 images with 1024x768 resolution that change very often doesn't.... or does it? The answer is very variable.
Also cache should always have storage boundaries. Even in the previous example with the large images, you could limit the cache to a a certain storage capacity.
Normally the cache saves a local copy of the most recently used items. But you can implement a more sophisticated algorithm, for example, saving the most visited images instead of caching the most recently used.

Local image caching solution for Android: Square Picasso, Universal Image Loader, Glide, Fresco?

I am looking for an asynchronous image loading and caching library in Android. I was going to use Picasso, but I found Universal Image Loader is more popular on GitHub. Does anyone know about these two libraries? A summary of pros and cons would be great.
(All my images are on disk locally, so I don't need networking, therefore I don't think Volley is a fit)
Update Sep 2018: After several years, I needed the almost same thing for a local image caching solution. This time around, UIL has not been in active development. I compared the popular libraries, and the conclusion is pretty no-brainer: just use Glide. It's much more powerful and configurable. Years ago I had to fork and make changes to UIL. Glide supports all my use cases in terms of caching strategy and multiple levels of resolution caching with custom keys. Just use Glide!
Koushik Dutta's comparison is mostly for speed benchmark. His post only touched very basic things, and is not specific for local images. I'd like to share my experiences with Picasso and UIL after I asked the question. Both Picasso and UIL can load local images. I first tried Picasso and was happy, but later I decided to switch to UIL for more customization options.
Picasso:
Picasso's fluent interface is nice. But jumping around with "with", "into", "load" you actually don't know what's behind the scene. It's confusing what's returned.
Picasso allows you to specify exact target size. It's useful when you have memory pressure or performance issues, you can trade off some image quality for speed.
Images are cached with size in its key, it's useful when you display images with different sizes.
You can customize the memory cache size. But its disc cache is only for http requests. For local images, if you care about loading speed, it's good to have a thumbnail disk cache so you don't have to read several MBs for an image every time. Picasso does not have this mechanism resizing and saving thumbnails on disk.
Picasso does not expose the access to its cache instance. (You can get a hold of it when you first configure Picasso and keep it around...).
Sometimes you want to asynchronously read image into a bitmap returned by a listener. Surprisingly Picasso doesn't have that. "fetch()" dose not pass back anything. "get()" is for synchronously read, and "load()" is for asynchronously draw a view.
Picasso only has a few simple examples on the homepage, and you'll have to read through the unordered javadoc for advanced usages.
UIL:
UIL uses builders for customization. Almost everything can be configured.
UIL does not allow you to specify the size you want to load into a view. It uses some rules based on the size of the view. It's not as flexible as Picasso. I have no way to load a lower resolution image to reduce memory footprint. (Edit: this behavior can be easily modified by adding an ImageSize argument in in the source code and bypass the view size checking)
UIL provides customizable disc cache, you can use this to cache the thumbnails with specified size. But it's not perfect. Here are the details. (Edit: if you care about speed and want multiple levels of thumbnail caching, like my case, you can modify the source code, let the disk cache use "memoryKey", and make it also size sensitive)
UIL by default caches images of different sizes in memory, and it can be turned off in configuration.
UIL exposes the backing memory and disk cache you can access.
UIL provides flexible ways you can get a bitmap or load to a view.
UIL is better in documentation. UIL gives the detailed usages on the Github page, and there's a linked tutorial.
I suggest starting with Picasso, if you need more control and customization, go for UIL.
If you read this post on G+ by Koush you will get clear solutions for your confusions, I have put the summary of that, in that Android-Universal-Image-Loader is the winner for your requirement!
Picasso has the nicest image API if you are using network!
UrlImageViewHelper + AndroidAsync is the fastest. Playing with these
other two great libraries have really highlighted that the image API
is quite dated, however.
Volley is slick; I really enjoy their pluggable backend transports,
and may end up dropping AndroidAsync in there. The request priority
and cancellation management is great(if you are using network)
Android-Universal-Image-Loader is the most popular one out there
currently. Highly customizable.
This project aims to provide a reusable instrument for asynchronous
image loading, caching and displaying. It is originally based on Fedor
Vlasov's project and has been vastly refactored and improved since
then.
Upcoming changes in new UIL version (1.9.2):
Possibility to call ImageLoader out of UI threadNew Disk Cache API
(more flexible). New LruDiscCache based on Jake Wharton's
DiskLruCache.
Considering all this Android-Universal-Image-Loader suites your requirement (Loading the images are on disk locally)!
I would like to share my experience with these 3 libraries: UIL, Picasso and Volley. I previously used UIL but then I came to the conclusion I can't really recommend it and I would suggest to use Volley or Picasso instead which are both developed by highly talented teams. UIL is not bad at all but it lacks the attention to detail of the other two libraries.
I found UIL being less nice with the UI performance; it tends to lock up the UI thread more than Volley or Picasso. This may be in part due to the fact that UIL does not support batching the image responses while Picasso and Volley do that by default.
Also, I didn't like the disk cache system of UIL. While you can choose between various implementations, I need to point out that at the moment there is no way to limit the UIL disk cache both by total size and by entity expiration time. Volley and Picasso do that, and they use the expiration time returned by the server by default while UIL ignores it.
Finally, UIL allows you to set a global image loader configuration which includes the selected disk cache and memory cache implementations and settings and other details, but this configuration will be applied everywhere in your app. So if you need more flexibility like two separate disk caches, it's a no go for UIL. Volley on the other hand allows you to have as many separate image loaders as you want, each with its own configuration. Picasso uses a global instance by default but also allows you to build separately configurable instances.
To sum it up: Picasso has the best API but it uses the global HTTP disk cache shared between all HttpURLConnection instances, which can be too restrictive in some cases. Volley has the best performance and modularity but is less user friendly and will require that you write a module or two of your own to make it work like you want. Overall I would recommend them both against UIL.
Edit (Dec 18 2014): Things have changed since I wrote this initial answer and I felt it was necessary to improve it:
Picasso 2.4 is even more configurable than older releases, and when used with OkHttp (which is highly recommended) it is also able to use a separate disk cache for each instance so there is really no restriction in what you can do.
More importantly, I noticed that the performance of Picasso and OkHttp has improved a lot and in my opinion it's now the fastest image loader solution for Android, period. Please note that in my code I always use .fit() in combination with .centerCrop() or .centerInside() to lower memory usage and avoid bitmap resizes on the UI thread. Picasso is actively developed and supported and that's certainly a big plus.
Volley hasn't changed that much but I noticed two issues with it in the meantime:
Sometimes under heavy load, some images are not loaded any more because of some disk cache corruption.
Thumbnails displayed in a NetworkImageView (with its scale type set to centerCrop) are quite blurry compared to what you get with the other libraries.
For these reasons I decided to stop using Volley.
UIL is still slow (especially the disk cache) and its API has a tendency to change quite often.
I also tested this new library called Glide 3 which claims to be more optimized than Picasso with a Picasso-like API. According to my personal experience it's actually slower than Picasso and Volley during network requests under heavy load, even when used in combination with OkHttp. Worse, it caused a few crashes with my apps under Lollipop when leaving an activity. It still has 2 advantages over its competitors:
It supports animated GIFs decoding
It puts the final downscaled bitmaps in the disk cache, which means reading back from the disk cache is extremely fast.
Conclusion: I now recommend to use Picasso + OkHttp because it provides the best flexibility, API, performance and stability combined. If you need GIF support you can also consider Glide.
I have implemented an app that should constantly get and show images from the internet. I was about to program an image cache mechanism, before that a friend recommended me the universal image loader.
The UIL is very good customizable. It's so customizable that a newbie can easily make something wrong. However, the UIL was slow in my application and it became a bit slower. My use case was a ListView with images.
Yesterday I was looking for an alternative to the UIL, and I discovered Picasso. Picasso was easy to integrate and to use: Just Picasso.context(context).load(url).into(imageview) and the image could be faster and smoothly be integrated.
For me, Picasso is definitely the API to use. My experience with UIL wasn't good.
I think ImageLoader is more customizable and flexible comparing to Picasso library.

Android Photo / Thumbnail Strategy using DiskLRUCache

I'm using Jake Wharton's DiskLruCache lib.
I'm curious about app performance, caching strategy, using caching both in a view and across a whole application. Most of the time, the image won't change.
Let's say for example I have a 320x320 photo on my server. I open the stream, save the image.
In my list views, I show bitmaps and in the detail, I show a larger image. Should I save a thumbnail bitmap too? Is that more efficient?
What is your experience with sharing the cache "object" across the entire app (let's say I have multiple views that might leverage the same data. What are the issues with this?
For the sake of performance and currency, what if the image changes on the server. What's the best strategy to know that it's changed? I don't have access to modified date. Only size and yet, I don't really want to query size every time either. Set a flag in the app on the server and then query the flag?
In a traditional application (if there is such a thing), what's the best practice for clearing the cache from time to time? (indent weirded out.)
(I was inspired to write this after seeing all of the performance improvements by Facebook in iOS. I don't have billions to do caching but I would like to at least be smart about it! LOL)
A lot of these answers depend on the type of app you're writing, how important image updates are (and how likely images will change, etc), and total images produced. Aside from disk caching, you should be using memory caching as well, especially in ListViews and other areas where the same images will be scrolled through repeatedly. Look at LruCache and read the Caching Bitmaps entry from Google.
320x320 is probably too big for a listview, you will likely want to create thumbnails (depending on device, and how you're implementing your listviews).
1) You should be using Disk caching fairly aggressively (how you define that is up to the app you're writing). Use the external storage directory, and if they have a few GB left over, it's not an issue if you take 100 mb for your app for instance. It can all be cleared away if it's ever needed anyway.
2) There shouldn't be an issue. Disk IO (even to a flash medium) should never be handled on the main thread. Use AsyncTasks to load the images. There can only be one main foreground activity at once anyway, and while an activity is sleeping, it shouldn't be trying to read from the disk anyway.
3) Again this depends on how you're implementing your app. You should be able to get additional information when retrieving the file (even Apache can tell your app the last modified date).
3.1) You can have a sqllite db that keeps track of how often certain images are used, and most recent read. If the most recent read is a few days old, let that image expire.
Edit: There's a library from Jake Wharton now called Picasso that I would recommend using, which handles the Network/local IO as well as memory and disk caching. Check it ou here: http://square.github.io/picasso/ . A lot of what you will need to do can be accomplished with one line: Picasso.with(this).load(imageFileURL).into(imageView);

removing image data from memory

I have to believe there's a way to clear image data from memory once it's no longer required, but despite exhaustive searching I can't find a solution. Both stack and the google android dev list are full of questions regarding OOM errors, specifically "bitmap size exceeds VM budget", but I still don't see a clear answer.
I understand there are hard memory limits on devices, and I understand it's not realistic to load up and display or cache large amounts of image data, but there should be away to discard data that's no longer required.
For example, imagine this very basic hypothetical app, that emulates a lot of the behavior of the native gallery app:
An image gallery that allows the user to peruse images from a remote server.
There might be any number of images on that server.
The app displays 1 image at a time, and allows a user to go back or forward 1 image at a time through button presses or swiping.
There'd be a maximum of 3 images rendered at any one time (so the user can see the one immediately to the left or right of the current image when swiping). All other image data should be discarded.
Images are loaded using URL.openStream and Drawable.createFromStream or BitmapFactory.decodeStream. Streams are closed appropriately.
Images are sized appropriately on the server before being fetched.
Loading happens in AsyncTasks. Tasks that are no longer needed (due to moving away from an image with an incomplete task) are cancelled. Any references in the AyncTask are WeaklyReferenced.
When any image is no longer required, it's "cleared" via:
getBackground().setCallback(null)
Listeners are set to null
setImageDrawable/Bitmap(null)
removeView
This simple construct, that takes into account all the suggest practices I'm aware of, will inevitably crash with an OOM error at some point. Using BitmapFactory.Options inSampleSize and inPreferredConfig will delay the inevitable, but not forever, and at the cost of image quality. In this example, I've used remote images, but the issue exists with images stored in /assets/ or in internal memory, etc.
My feeling is that if we can display X amount of image data at one point, and we take all steps to remove that image data from memory, we should be able to display that same amount of data later, without having to compensate for what has happened before.
With the sheer quantity of questions about this very issue, I'd hope to have a standard solution documented, but if there is one, I can't find it. I've seen answers posted by Romain Guy, who otherwise seems very generous with his knowledge and active in the community, that say something like "Simple. Don't use so much memory". OK. Tell me how.
I should also mention that System.gc does nothing to help this. I'm also aware of bitmap.recycle, but unless I'm mistaken this can't be used in this fashion.
Am I missing something fundamental? Is there a way to discard image data once it's no longer being used? What is missing from the above to create a simple photo gallery? Assuming the built-in gallery app uses the framework and not the NDK, I imagine there has to be a way...
TYIA.
/this question has also been posted on the android developer google group list.
Through my work with Prime I found a few tips, one of which you have not mentioned. When you decode your Bitmaps make sure to use the inPurgeable and inInputShareable flags in your BitmapFactory.Options. That will help a little bit but I would recommend you look at my implementation of image loading in Prime. I use it in all of my products without any memory issues. I have found that 95% of memory problems are from the incorrect usage of the Bitmap class.
There is a very detailed article about the use of bitmaps on the android developer website.
Did you look at it ?
It explains how to load, cache and display bitmaps efficently and how to get rid of this famous OutofMemoryError.
There is also a sample application from an image gallery.
I think that's what you're looking for.

Categories

Resources