Posted by Michael S., Android Engineer

Dynamically loaded images are a cornerstone of many Android applications. At Yelp, images are critical to how we connect consumers with great businesses. As network connections and device hardware have become more powerful, the quantity and quality of images that users have come to expect has continued to increase. Images can easily become the largest consumer of device memory and network data, and handling the downloading and management of this data becomes a daunting task. We explored several solutions to this problem, and ultimately decided that Glide provided a great combination of performance, ease of use, and a robust feature set.

Glide, in the simplest use case, will load images either from a remote server or the local file system, put them into disk and memory based caches, and then load them into views. While it can be used for pretty much all images in an app, Glide is optimized for scrolling lists that contain images as smoothly as possible.

The Object Pool

At the center of Glide’s approach is keeping an object pool data structure for bitmaps. The main goal of an object pool is to increase performance by reducing the number of large object allocations and instead reuse them (for an overview of object pools, check out this Android performance pattern video).

Both the Dalvik virtual machine and ART (for the moment) don’t use a compacting garbage collector, a model in which the GC will run through the heap and move living objects into adjacent memory locations, leaving larger chunks of memory available for future allocations. Because Android doesn’t use this model, the heap can end up in a situation where allocated objects are spread out with only small chunks of available memory in between them. If the application tries to allocate an object that is bigger than the largest contiguous chunk of free memory it will run into an OutOfMemoryError and crash, even if the total amount of free memory was greater than the size of the object.

Using an object pool also helps scrolling performance because reusing bitmaps means fewer objects are created and garbage collected. Garbage collection passes cause “stop the world” events where all threads (including UI) are paused while the collector is executing. During this time, frames can’t be rendered and the UI may stall, which is especially noticeable during scrolling.

Review images

Using Glide

Glide is simple to get up and running, and it automatically includes bitmap pooling without any special configuration.

DrawableRequestBuilder requestBuilder = Glide.with(context).load(imageUrl);

requestBuilder.into(imageView);

That’s all that is required to begin loading an image. As always with Android, it can be unclear what type of context to pass into the with() method. It is important to note that the type of context passed in affects how much Glide can optimize loading. If an Activity context is passed in, Glide will monitor the activity lifecycle methods and automatically cancel pending requests if it sees the activity is starting to tear down. However, if an Application context is used, you lose out on this optimization.

Optimization Features

Along the same lines, Glide automatically cancels pending requests for images in a ListView if the associated list item is scrolled off the screen. Since most developers take advantage of view recycling in their adapters, it does this by attaching a tag to the ImageView when requesting an image, checking for that tag before loading another image, and canceling the first request if it exists.

Glide provides a few features that give the impression of faster image loading. The first is the ability to prefetch images in a list before they are shown on the screen. It provides a ListPreloader class, which is instantiated with the number of items ahead it should prefetch. That is then passed to the ListView through setOnScrollListener(OnScrollListener). Need to prefetch images outside of a ListView as well? Not a problem, that is supported as well. Using the builder object above, simply call builder.downloadOnly(); .

We’ve found the out-of-the-box utility that Glide provides has greatly increased the performance, reliability, and aesthetics of the areas in our Android application that load images. The availability of these additional features and optimizations really allow applications to fine tune their image loading experience into something that creates a delightful experience for the user.