Google I/O 2013: Volley Image Cache Tutorial

by Raymond Robinson Steven Byle

Google I/O 2013 has come to an end, and it has left us with great anticipation for the future of Android development. One of the more exciting things on display at I/O this year was a library called Volley. Volley is a library that handles the processing and caching of network requests, which saves developers from writing the same boilerplate code in virtually every application. Writing boilerplate code is never fun and is increases the chances of a mistake by the developer. It is with this in mind that Google has created Volley.

If you have not seen the Google I/O presentation on Volley, I encourage you to go watch it to get an understanding of the basics before continuing with this article. 

During the Google I/O presentation, Ficus Kirpatrick talks a lot about how Volley helps with image loading. When implementing Volley as your image loading solution you will find that, while it does handle L2 caching on its own, it requires but does not include an L1 image cache out of the box. Many people have used things like the Universal Image Loader or Square’s newer Picasso library to handle image loading; however, these libraries typically handle both the loading and the caching of the images already. So, how do we load and cache images with Volley instead? First, let’s look at what Volley provides to facilitate loading, we can fill in the other gaps later. 


The ImageLoader class takes an instance of the request as well as an implementation of an ImageCache.  Images are loaded by passing a URL and an instance of an ImageListener to the get() method. From there, the ImageLoader checks the ImageCache, and if the image is not in the cache, loads the image from the network.


This class replaces ImageViews in your layout and will use the ImageLoader.  The setUrl() method of the NetworkImageView takes a string URL path as well as an instance of the ImageLoader. It then uses the ImageLoader’s get() method to retrieve its image data.




The Volley ImageCache interface allows you to use your preferred L1 cache implementation. Unfortunately, one of the shortcomings of Volley (and the reason for this article) is that there is no default cache implementation. The I/O presentation shows a code snippet for BitmapLruCache, but the library itself does not include any such implementation. 

The ImageCache interface has two methods, getBitmap(String url) and putBitmap(String url, Bitmap bitmap). These stubs are straightforward enough that they can be added to any cache implementation. 

Filling in the Gaps: Adding an Image Cache to Volley

For this example, I have created a simple app, which searches for references to "CapTech" via Twitter and displays the tweets with username and photos in a list view. The list will automatically load older records as your scroll down, and pull images from the cache as needed.



There are two available cache implementations. The recomended approach uses a basic in memory LRU cache. For the disk cache implementation I chose to use the DiskLruCache written by Jake Wharton. I chose this implementation because it is frequently used in the Android community and represents a common use case for someone trying to retrofit their application for Volley. Using a disk based L1 cache may cause i/o blocking issues. Volley already has an implicit disk L2 cache. The disk L1 cache is included because I was originally unaware of how Volley handled image request caching. 

The main components of this implementation are as follows:


The RequestManager maintains a reference to our RequestQueue. Volley uses the RequestQueue to handle both our requests for Twitter data and our image loading.


This is not directly related to image loading but it is representative of how you might extend the Volley Request class to handle your JSON parsing for you. This is used for the GET request to Twitter and the resultingTwitterData object.


This is a basic "least recently used" in memory cache implementation. It is fast and does not block I/O. This is the recommended approach.


The DiskLruImageCache is a wrapper for the DiskLruCache with a bitmap-centered implementation. It adds and retrieves the bitmaps from the DiskLruCache, and handles the cache instantiation. A disk cache may block I/O.


The ImageCacheManager holds a reference to both our ImageCache and our Volley ImageLoader.

One thing you will notice in the ImageCacheManager is that we use a hashCode() value of the URL string as the key to the cache. This is done because some of the characters in the URL are not supported in the cache key.


The adapter is straightforward. The only thing to note here is that we implement the Volley Listener and ErrorListener interfaces and pass the adapter as the Listener in the call to the NetworkImageView’ssetUrl(String string , Listener listener, ErrorListener errorListener) method. This adapter has a little extra code to load older tweets as your scroll.


Tweet tweet = mData.get(position);
if(tweet != null){
	viewHolder.twitterUserImage.setImageUrl(tweet.getUserImageUrl(), ImageCacheManager.getInstance().getImageLoader());
	viewHolder.userNameTextView.setText("@" + tweet.getUsername());
	viewHolder.destinationUrl = tweet.getDestinationUrl();

Putting it all together

With all of these pieces in place, image loading and caching are now incredibly simple. On startup, the application initializes the RequestManager and the ImageCacheManager in the MainApplication class. It is here that you can declare your desired L1 cache type. An in memory cache is the default.  

In MainActivity we make our first call to the TwitterManager and load our initial set of data. Once we receive the response we pass it along to a BuzzArrayAdapter and set the adapter on our ListView.

As we have already seen in the BuzzArrayAdapter code above, the NetworkImageView does all of the heavy lifting in the image loading operation we just need to pass an instance to our image loader, which we can get from our ImageCacheManager.

The ImageCacheManager checks our LRU cache implementation and returns the image if it is available. If the image is not in the cache it is retrieved from the network.

As you scroll the ListView the BuzzArrayAdapter will load additional tweets along with their images, and reuse images that already exist in the cache.

Closing Thoughts on Volley

Although Volley is useful, fast, and very easy to implement; there are a few reasons it is not quite ready for prime time:

  • The library lacks any documentation or examples.  
  • Components such as cache configuration, are not as configurable as I would like them to be.  
  • As seen above, the exclusion of a base image cache implementation is strange. It may even be useful to include a NoImageCache implementation or perhaps making caching optional altogether for those times when you just want to get everything from the network.

There is a lot of excitement in the development community about Volley, and for good reason. It really feels like a library that should have been included long ago as a part of the Android API. Much like the new Location API unveiled at I/O, it is very clear that Google is interested in making the lives of programmers easier by removing the boilerplate barrier from app development.

Source on Github