Jetpack Compose is a modern toolkit for building native UI on Android. It simplifies and accelerates UI development with declarative and reactive programming. One of the common tasks in UI development is to display images from various sources, such as network, local storage, assets or resources. In this blog post, we will explore how to load images in Jetpack Compose using different libraries and techniques.
Loading images from disk
To load an image from disk, such as a PNG, JPEG, WEBP or vector resource, we can use the Image
composable with the painterResource
API. The painterResource
function takes an image reference (such as a resource ID) and returns a Painter
object that can be used to draw the image on the screen. We don’t need to know the type of the asset, just use painterResource
in Image
or paint modifiers1.
For example, to load an image from a resource:
Image( painter = painterResource(id = R.drawable.dog), contentDescription = stringResource(id = R.string.dog_content_description) )
To ensure that our app is accessible, we should supply a contentDescription
for visual elements on screen. TalkBack reads out the content description, so we must ensure that the text is meaningful if read out loud and translated. In the above example, we use a stringResource
function to load up the translated content description from the strings.xml
file. If our visual element on screen is purely for visual decoration, we can set our contentDescription
to null for the screen reader to ignore it1.
If we need lower-level ImageBitmap
specific functionality, we can use ImageBitmap.imageResource
function to load up a bitmap. For more information on ImageBitmaps
, read the ImageBitmap versus ImageVector section1.
Loading images from the internet
To load an image from the internet, there are several third-party libraries available that can help us handle the process. Image loading libraries do a lot of the heavy lifting for us; they handle both caching (so we don’t download the image multiple times) and networking logic to download the image and display it on screen1.
Some of the popular image loading libraries for Jetpack Compose are:
- Coil: An image loading library backed by Kotlin Coroutines (Instacart)21.
- Glide: A fast and efficient image loading library for Android focused on smooth scrolling (Google)1.
- Fresco: An image loading library that supports a variety of image formats and sources (Facebook)3.
- Landscapist: A pluggable, highly optimized Jetpack Compose image loading solution that fetches and displays network images with Glide, Coil, and Fresco. This library supports tracing image loading states, composing custom implementations, and some valuable animations, such as crossfades, blur transformation, and circular reveals (skydoves)23.
To use any of these libraries in our Android app, we need to add the corresponding dependency to our build.gradle
file. Then, we can use their provided composables or extensions to load an image from a URL.
For example, to load an image with Coil:
AsyncImage( model = "https://example.com/image.jpg", contentDescription = "Translated description of what the image contains" )
To load an image with Glide:
GlideImage( model = "https://example.com/image.jpg", contentDescription = "Translated description of what the image contains" )
To load an image with Fresco:
FrescoImage( model = "https://example.com/image.jpg", contentDescription = "Translated description of what the image contains" )
To load an image with Landscapist:
NetworkImage( imageUrl = "https://example.com/image.jpg", contentDescription = "Translated description of what the image contains" )
We can also configure the requests with optional parameters or lambdas to customize the loading behavior and appearance of the images.
Code examples
Here are some code examples of using different libraries to load images from the internet in Jetpack Compose:
Loading an image with Coil
AsyncImage( model = "https://coil-kt.github.io/coil/logo.svg", contentDescription = "Coil logo", modifier = Modifier.size(200.dp), loading = { Box(Modifier.matchParentSize()) { CircularProgressIndicator(Modifier.align(Alignment.Center)) } }, error = { Image( painter = painterResource(id = R.drawable.error), contentDescription = "Error image" ) } )
Loading an image with Glide
GlideImage( model = "https://coil-kt.github.io/coil/logo.svg", contentDescription = "Coil logo", modifier = Modifier.size(200.dp), requestBuilder = { crossfade(true) placeholder(R.drawable.placeholder) error(R.drawable.error) } )
Loading an image with Fresco
FrescoImage( model = "https://coil-kt.github.io/coil/logo.svg", contentDescription = "Coil logo", modifier = Modifier.size(200.dp), controllerBuilder = { autoPlayAnimations(true) placeholderImage(R.drawable.placeholder) failureImage(R.drawable.error) } )
Loading an image with Landscapist
NetworkImage( imageUrl = "https://coil-kt.github.io/coil/logo.svg", contentDescription = "Coil logo", modifier = Modifier.size(200.dp), loading = { ShimmerParams( baseColor = Color.LightGray, highlightColor = Color.White, dropOff = 0.65f ) }, failure = { Image( painter = painterResource(id = R.drawable.error), contentDescription = "Error image" ) }, success = { RevealCircularTransition( durationMillis = 600, delayMillis = 100 ) } )