In the mobile world, it’s very common to have scrollable lists of items that contain information and an image or two. To make these lists performance well, most apps follow a lazy loading approach, which simply grabs and displays images in these types of lists.
This approach works great for getting images into the system initially. However, there are still a few problems with this approach. The app must re-download each image every time the images need to appear to the user in the list.
This creates a pretty bad experience for the user. The first time the user sees the list, s/he has to wait several seconds (or minutes with a bad network connection) before s/he sees the complete list with images. But the real pain comes when the user scrolls to a different part of the list and then scrolls back. This action causes the entire image download process to restart!
We can remove the negative user experience by using a image cache.
An image cache allows us to store images on the device that have been recently downloaded. By storing them on the device, we can grab them from memory instead of asking the server for them again. This can save us performance in several different ways, most notably:
There are some design considerations when using a cache. Since the cache is using memory on the device, it is fairly limited on space. This means we can only have a certain number of images in the cache, so it’s really important to make sure we keep the correct images stored there. “Correct” is a very relative term, which can mean several different things based on what problem is at hand. As you can see here, there are several different types of caching algorithms that attempt to define “correct” for different problems. In our case, “correct” means we want the images that are used the most in the cache.
Luckily for us, the type of cache we need is simple and one of the most commonly used. The LRU Cache keeps the most frequently used images in memory, while discarding the least used images. And even luckier, the Android SDK has a LRUCache implementation, which was added in Honey Comb (its also available on the Support Library if you need to support older versions as well).
A LRU Cache allows you to save images in memory instead of going to a server every time. This allows your app to respond much quicker to changes and save some battery life. One of the limits of the cache is the amount of memory you can use to actually store the images. This space is very constrained, especially on mobile devices.
However, you do have access to one data store that has considerably more space: the disk.
The disk on a mobile device is usually much larger than the main memory. Although disk access is much slower than main memory, it is still much faster than going to the network for an image, and you still get the battery life savings by not going to the network.
For an excellent Disk LRU Cache implementation that works great with Android, check out Jake Wharton’s DiskLRUCache on GitHub.
Although both of the previous caches (memory LRUCache and disk LRUCache) work well independently, they work every better when combined. By using both caches at the same time, you get the best of both worlds:
Combining the two caches is fairly straight forward.
Google provides some excellent example code for both the memory and disk caches here. All you have to do now is take the two different cache implementations and use the above flow chart to put them together to create a Level 2 image cache in Android!