views:

169

answers:

2

Hello all,

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.

+1  A: 

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.

BenTobin
I like your thought about preventing the gallery from seeing the images. Under what conditions would the gallery pick them up though? I have yet to see random pictures and I know there are some apps like twidroid on my phone that cache them.
smith324
@chris324 Take a look at http://developer.android.com/guide/topics/data/data-storage.html#filesExternal under the title 'Saving files that should be shared'
Eric
@Eric thanks for the link, looks like an external directory with an empty file named `.nomedia` will be ignored by the mediascanner.It also looks like getExternalCacheDir() is new in 2.2 which will be useful.
smith324
Ah, I was unaware of .nomedia. Some of the apps that have loaded images to the SD card that have shown up in the gallery are "My Maps Editor" (By Google, no less!), CauseWorld, and at least one music app I tried. The ones I still have installed seem to have fixed the problem since then.
BenTobin
@BenTobin That has been annoying me for some time too, and this conversation decided me to do something about it. It turns out creating the `.nomedia` file from the computer ( `touch /Volumes/MYPHONESSDCARD/maps/mymaps/icons/.nomedia` ) has removed those images from the gallery.
Eric
if you are going to use .nomedia directory, make sure you read the following issue also: http://code.google.com/p/android/issues/detail?id=3692. My 2 cents!
Samuh
@Samuh, thats for that. Well its certainly a serious bug, but if I read everything correctly as long as I put `.nomedia` in the directory before writing any files to it everything *should* be ok. (andrew.schwimmer's explanation was enlightening)
smith324
+1  A: 

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!

The Alchemist
Interesting read. I like the notion of using a combined hard/soft reference cache. Fine tuning the cache size based on the available heap seems like over kill to me though, esp since the VM will give you about the same amount on each phone.
smith324