When implementing image loading in Jetpack Compose, use
Coil
(Coroutines Image Loader). It is the recommended library for Compose due to its efficiency and seamless integration.
1. Primary Composable:
AsyncImage
Use
AsyncImage
for most use cases. It handles size resolution automatically and supports standard
Image
parameters.
AsyncImage
(
model
=
ImageRequest
.
Builder
(
LocalContext
.
current
)
.
data
(
"https://example.com/image.jpg"
)
.
crossfade
(
true
)
.
build
(
)
,
placeholder
=
painterResource
(
R
.
drawable
.
placeholder
)
,
error
=
painterResource
(
R
.
drawable
.
error
)
,
contentDescription
=
stringResource
(
R
.
string
.
description
)
,
contentScale
=
ContentScale
.
Crop
,
modifier
=
Modifier
.
clip
(
CircleShape
)
)
2. Low-Level Control:
rememberAsyncImagePainter
Use
rememberAsyncImagePainter
only when you need a
Painter
instead of a composable (e.g., for
Canvas
or
Icon
) or when you need to observe the loading state manually.
[!WARNING]
rememberAsyncImagePainter
does not detect the size your image is loaded at on screen and always loads the image with its original dimensions by default. Use
AsyncImage
unless a
Painter
is strictly required.
val
painter
=
rememberAsyncImagePainter
(
model
=
ImageRequest
.
Builder
(
LocalContext
.
current
)
.
data
(
"https://example.com/image.jpg"
)
.
size
(
Size
.
ORIGINAL
)
// Explicitly define size if needed
.
build
(
)
)
3. Slot API:
SubcomposeAsyncImage
Use
SubcomposeAsyncImage
when you need a custom slot API for different states (Loading, Success, Error).
[!CAUTION]
Subcomposition is slower than regular composition. Avoid using
SubcomposeAsyncImage
in performance-critical areas like
LazyColumn
or
LazyRow
.
SubcomposeAsyncImage
(
model
=
"https://example.com/image.jpg"
,
contentDescription
=
null
,
loading
=
{
CircularProgressIndicator
(
)
}
,
error
=
{
Icon
(
Icons
.
Default
.
Error
,
contentDescription
=
null
)
}
)
4. Performance & Best Practices
Singleton ImageLoader
Use a single
ImageLoader
instance for the entire app to share the disk/memory cache.
Main-Safe
Coil executes image requests on a background thread automatically.
Crossfade
Always enable
crossfade(true)
in
ImageRequest
for a smoother transition from placeholder to success.
Sizing
Ensure
contentScale
is set appropriately to avoid loading larger images than necessary.
5. Checklist for implementation
Prefer
AsyncImage
over other variants.
Always provide a meaningful
contentDescription
or set it to
null
for decorative images.
Use
crossfade(true)
for better UX.
Avoid
SubcomposeAsyncImage
in lists.
Configure
ImageRequest
for specific needs like transformations (e.g.,
CircleCropTransformation
).