Best Practice when Caching files in Android - android

I currently have my app caching image files in the cache sub-directory for the application. The images are used in a ListView and stored in a HashMap of SoftReferences to Bitmaps.
So my question is this, what is the best way to cache these image files without inflating the space my application uses AND remains responsive from a user standpoint.
Things I am concerned about:
I know the user can clear the cache and that it is done automatically when space is low on internal memory, but I feel most users will see a several MB app and uninstall it. Also if the space is constantly low, my app will just keep downloading the images, making it appear slower.
Most devices have an SD card pre-installed, but what should I do when it is not inserted? The SD card may also be slower compared to internal storage, affecting my app's performance.
Should I include an option to choose the location of the cache?
Should I attempt to manage the size of my cache (be it in the /cache or /sdcard) or just forget about it?
Thank you for your time (its a long one I know) and please post any relevant experience.

I can't offer you a comprehensive set of best practices, but I can offer what I've learned so far:
Managing your cache is a good idea. My app's cache is such that I know that I'll never need more than a certain number of cached files, so whenever I insert a new file into the cache, I delete the oldest files until I'm under the limit I have set. You could do something similar based on size, or simply age.
Caching to the SD card, if it's available, is a good idea if your cache needs to take up a lot of space. You'll need to manage that space just as carefully, since it won't automatically clear that space for you. If you're caching image files, be sure to put them in a directory that begins with a dot, like "/yourAppHere/.cache". This will keep the images from showing up in the gallery, which is really annoying.
Letting the user choose the location of the cache seems like overkill to me, but if your audience is very geeky, it might be appreciated.
I haven't noticed a much of a penalty when caching to the SD, but I don't know how your app uses that information.

Everyone has good ideas. I like the idea of using SoftReference's, although I'm not sure how often those get cleaned up, as this varies so much from VM to VM. You might want to combine that with regular HashMap to prevent you entire cache getting cleared every few minutes.
EclipseLink has a few different cache implementations and pretty good documentation on them. You could probably take advantage of a few ideas from the implementation (e.g., LRU, MRU, etc.). e.g.,
hard cache
soft cache
combined hard/soft cache
Since you're tuning a cache down to the nitty-gritty, I would recommend tuning it to different devices based on the hard specs. This is normally bad design, but the scope of the hardware that your software runs on mandates it, IMHO. e.g.,
Detect the amount of available memory on the SD card. Most new smart phones come with multi-GB SD cards, and those are pretty hard to fill up with regular usage for most users. Use away! You can also detect the amount of space available on the SD card on startup, and increase/decrease the size of your cache on startup.
Detect the amount of available memory and configure your caches with that in mind. If a user is using a hardware-intensive application, I don't think they'll mind that it makes up 200MB of RAM and provides a very fast user experience, especially since they spent a lot of money to have a phone that has 1-2GB RAM.
Good luck!

Should I include an option to choose the location of the cache?
IMO: No, let make it more simplest as possible (Except you can include advance setting for expert user)
Should I attempt to manage the size of my cache (be it in the /cache
or /sdcard) or just forget about it?
IMO: This is optional, it is double sword: your more work on background will help user more convenience but also more bug prone
Use 3rd libs:
IMO using 3rd library as Picasso is better, it handle cache automatically by order: Memory cache -> Disk cache -> Network

Related

Self monitor cache directory

I am currently storing bitmap images inside my cache, each bitmap can be upto 3mb in size each. I am using getCacheDir() however, after reading androids documentation, I found this:
Note: you should not rely on the system deleting these files for you; you should always have a reasonable maximum, such as 1 MB, for the amount of space you consume with cache files, and prune those files when exceeding that space.
So I am considering switching my cache to using getExternalCacheDir(), but I am abit uncertain about this:
The platform does not always monitor the space available in shared storage, and thus may not automatically delete these files. Apps should always manage the maximum space used in this location. Currently the only time files here will be deleted by the platform is when running on JELLY_BEAN_MR1 or later and isExternalStorageEmulated(File) returns true.
I would like to have full control of the cache dir, because if files are randomly deleted this could really affect the running of my application. I have already set an upper limit for the size of the cache so it will never exceed a certain amount of space. How can I now prevent the system from monitoring and deleting from this cache as it pleases?
thanks
Don't think that cache is permanent storage. You mustn't store there files that you rely on. Cache used for storing data that you don't really want to reload or recreate, but you can do it if needed (as with loading pictures from web. Much faster to load from disk, if already done, but can be done without it). If you really depend on this files use getFilesDir() this will route you to specific app directory, that wouldn't be erased if no memory (but still can be erased by user in settings). Also, if you have data that is static and you need it always, you must store it in the assets folder, all other data must be considered as temporary (any time user or system can erase it) and checked for existence.

Android Glide alternate cache in memory or disk

I´m working in an App which does have images that are used quite often, however there are others download used only once.
Does Glide have any way for deciding on the fly which images should be stored only in Disk or only in memory?
As far as I´ve seen it does the cache depends on the configuration buy I´de like to be able to say by myself which ones should be in disk and which ones no.
You can use .diskCacheStrategy() to manually control whether and how an individual request is cached on disk and skipMemoryCache() to control whether an individual request is cached in memory.

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.

android Download hundreds of images and store them to be used on revisit or when the internet is not there

I have a listview and each listview item when clicked opens a gallery (conating 30 + images ) to be downloaded (using the urls).I don't want to re - download the images on next visit and also want the images to be present when i click on list in offline mode.
I went through several links in SO and am a bit confused on which approach to follow:
1> Use bytearray and store the images in sqlite db.
2> use context -> getExternalCacheDir() to store it on the
external memory (this wont work on devices with no external
memory.)
3> Use SoftReferences as suggested in following link
http://android-developers.blogspot.in/2010/07/multithreading-for-performance.html
Please help to guide me on the best approach to handle around 1000 + images which works in offline mode as well.
1000 images.....I sure hope they're thumbnails or you're going to end using a lot of storage space.
You should really only cache what you need and what images are used repeatedly. Both options 1 and 2 are dependant on the phone even having storage space, if there's no space then you won't be caching much to disk. 3 won't store images permanently, if the app is put in the background and gets killed and so will the cache.
It's hard to say what the correct decision here is without knowing the inner workings and requirements of the app.
Just going by what you want then I would say go with several solutions
If there's external storage write to that, if not use internal storage, if there's not enough space internally use the soft references.
I have always found that out of the box caching solutions never fit quite right with my apps and wind up writing my own cache. Sorry I can't give a better answer.
PS. If you're not careful with 3 you might download too much and run into an OutOfMemoryException.
PPS. 3 can also throw a RejectedExecutionException which is caused by too many async tasks being started at once (eg scrolling quickly through a listview that gets an image via asynctask)

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);

Categories

Resources