Coil Compose — Loading and Caching Images in Compose

Sudhanshu Kumar
3 min readNov 11, 2023

--

In this blog post, we’ll explore the efficient loading and caching of images from the network using the Coil library in Jetpack Compose. Coil is a modern, Kotlin-first image loading library that seamlessly integrates with Compose to provide a smooth and powerful image loading experience.

Setting Up Coil in Your Compose Application

To get started, we need to configure Coil in our Compose application. In your Application class, implement the ImageLoaderFactory interface and override the newImageLoader() function:

class GreenApplication : Application(), ImageLoaderFactory {
@OptIn(ExperimentalCoilApi::class)
override fun newImageLoader(): ImageLoader {
return ImageLoader.Builder(this)
.memoryCache {
MemoryCache.Builder(this)
.maxSizePercent(0.20)
.build()
}
.diskCache {
DiskCache.Builder()
.directory(cacheDir.resolve("image_cache"))
.maxSizeBytes(5 * 1024 * 1024)
.build()
}
.logger(DebugLogger())
.respectCacheHeaders(false)
.build()
}
}

Here, we’ve configured both memory and disk caches for optimal performance. Adjust the cache sizes according to your application’s requirements.

  • Memory Cache: This cache uses RAM to store images and gets cleared whenever the RAM is cleared. The memory cache is ideal for scenarios where you’re loading and displaying images in a LazyColumn. Since it uses RAM to store images, it provides fast access for frequently displayed images
  • Disk Cache: The disk cache is well-suited for storing larger images, such as banners or high-resolution graphics. While access from disk may be slightly slower than the memory cache, it provides persistence and is crucial for optimizing storage usage in your app.

Cache Configuration Details

In the code snippet, we’ve used

  • maxSizePercent: method to set the maximum size of the memory cache as a percentage of the available memory.
  • maxSizeBytes: method to set the maximum size for the disk cache.
  • respectCacheHeaders: If disabled, images will always be served from the disk cache (if present). By default it is set to true.

Composing with Coil

Now, let’s dive into composing with Coil. In a Composable function, you can load and display an image using the AsyncImage composable. Here's an example:

@Composable
fun SampleScreen() {
Surface(modifier = Modifier.fillMaxSize()) {
val context = LocalContext.current
val placeholder = R.drawable.gradient_sun
val imageUrl = "https://image_url.jpg"

// Build an ImageRequest with Coil
val listener = object : ImageRequest.Listener {
override fun onError(request: ImageRequest, result: ErrorResult) {
super.onError(request, result)
}

override fun onSuccess(request: ImageRequest, result: SuccessResult) {
super.onSuccess(request, result)
}
}
val imageRequest = ImageRequest.Builder(context)
.data(imageUrl)
.listener(listener)
.dispatcher(Dispatcher.IO)
.memoryCacheKey(imageUrl)
.diskCacheKey(imageUrl)
.placeholder(placeholder)
.error(placeholder)
.fallback(placeholder)
.diskCachePolicy(CachePolicy.ENABLED)
.memoryCachePolicy(CachePolicy.ENABLED)
.build()

// Load and display the image with AsyncImage
AsyncImage(
model = imageRequest,
contentDescription = "Image Description",
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop,
)
}
}

In this example, we’ve used the image URL as the cache key to check whether the image exists in the cache. You can customize the cache key generation according to your application’s specific needs.

  • We can specify our own dispatcher on which we want coil to load the image. Here we’ve used Dispatcher.IO for demonstration.

Clearing the Cache

In certain scenarios, you might need to clear the image cache programmatically. For example, you might want to provide users with an option to clear the cache to free up storage or ensure the latest images are fetched.

You can achieve this by adding a button or triggering the cache clearance function at an appropriate point in your application. Here’s a simple example using a Compose Button:

Button(onClick = {
context.imageLoader.diskCache?.clear()
context.imageLoader.memoryCache?.clear()
}) {
Text("Clear Image Cache")
}

If you want to remove a specific image from the cache, you can use the following code snippet:

context.imageLoader.diskCache?.remove("key")

Conclusion

Coil simplifies the process of loading and caching images in Jetpack Compose. By configuring the image loader and using the AsyncImage composable, you can efficiently handle image loading with ease. Customize the caching strategy and keys based on your application's requirements for a seamless user experience. Happy composing!

--

--