December 12, 2015
Posted by on
This is more of an announcement. I’ve uploaded a new opensource project, ImageCache. As the name suggests, it’s a component for Android that handles downloading and displaying images from the Internet. Basic call is like this:
CacheQueue.displayImage(imageView, "http://i.imgur.com/u0NjkvC.jpg", 600);
With this call, the component will download file from given URL, save it to disk (I kinda like saying disk, it’s not a disk though), open with dimensions around 600px on the longest side, and assign to the imageView. If the imageView somehow became irrelevant in the process (say the activity reloaded), then cache wouldn’t keep it and will just store the image. Naturally, subsequential calls for that same url will either pull the image from memory, or from the disk cache.
This sounds simple so far, and you might wonder why wouldn’t I just use AsyncTask for that like a normal person. As it turns out, there is more.
- What if we make lots of calls at the same time? In this case there has to be a strategy as to how many download threads to run. This cache is built on top of a custom LoaderTask component, which sets it to 5 concurrent threads. It is also organized in a way that was meant to reuse LoaderTask for other web operations in the app. You might not find it extremely convenient if you want a separate component, but for me it was a base layer of my app’s web operation.
- How do we limit the disk footprint? Might surprise you, but it’s really tricky to do right, because you can’t exactly afford to rescan the entire filebase on every sneeze. Most lazy cache implementations I’ve seen don’t even bother. They either just keep downloading files, or delete the entire cache when it becomes too large. This component keeps track of files using DB and deletes older files when it detects an overload.
- What if we have requested an image limited to 100px (thumbnail), and then immediately requested that same image in 2048px (fullsize) from the same url? This isn’t very hard to implement, but it’s one of those things that can be really annoying and easy to overlook. The component works with that.
Initially I developed this code as part of a Reddit client for a customer, but then I had rewritten it for my own purposes. Not sure if it’s very useful as an actual component (caching requirements often differ a lot), but you’re welcome to check it out if you’re building your own.