Coil3 with Compose | Issue using rememberAsyncImagePainter with multiple @Preview
#3.001 aberto em 29 de mai. de 2025
Métricas do repositório
- Stars
- (11.779 stars)
- Métricas de merge de PR
- (Mesclagem média 20h 14m) (28 fundiu PRs em 30d)
Description
Describe the bug
As shown in the image below, using rememberAsyncImagePainter doesn't seem to prompt all the necessary previews when combined with multiple @Preview.
It also seems to show the preview is out of date, even after rebuilding, also that might just be a red herring.
To Reproduce Here is a sample code to reproduce the issue presented above using sample code from the documentation available here.
package com.stash.android.sds.compose.components.content.test
import android.content.res.Configuration
import androidx.compose.foundation.Image
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import coil3.ColorImage
import coil3.annotation.ExperimentalCoilApi
import coil3.compose.AsyncImagePainter
import coil3.compose.AsyncImagePreviewHandler
import coil3.compose.LocalAsyncImagePreviewHandler
import coil3.compose.rememberAsyncImagePainter
@OptIn(ExperimentalCoilApi::class)
@Composable
internal fun CoilPreviewBug(
) {
val previewHandler = AsyncImagePreviewHandler { ColorImage(Color.Red.toArgb()) }
CompositionLocalProvider(
LocalAsyncImagePreviewHandler provides previewHandler,
) {
val painter = rememberAsyncImagePainter("https://example.com/image.jpg")
val state by painter.state.collectAsState()
when (state) {
is AsyncImagePainter.State.Empty,
is AsyncImagePainter.State.Loading -> {
CircularProgressIndicator()
}
is AsyncImagePainter.State.Success -> {
Image(
painter = painter,
contentDescription = null,
)
}
is AsyncImagePainter.State.Error -> {
// Show some error UI.
}
}
}
}
@Composable
@Preview(name = "1 - Light Mode", device = Devices.PIXEL_4_XL)
@Preview(name = "2 - Dark Mode", uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_4_XL)
@Preview(name = "3 - Light Mode - Large", device = Devices.PIXEL_4_XL, fontScale = 2.0f)
internal fun CoilPreviewBugPreview() {
CoilPreviewBug()
}
As a side note, I was able to show all previews using the code below. However, I am unsure if the way I set up my code is the recommended approach. I would have expected rememberAsyncImagePainter to work with any number of previews.
val previewHandler = AsyncImagePreviewHandler { ColorImage(Color.Red.toArgb()) }
CompositionLocalProvider(
LocalAsyncImagePreviewHandler provides AsyncImagePreviewHandler { previewHandler },
) {
val painter = rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalPlatformContext.current)
.data("https://example.com/image.jpg")
.build(),
)
val state by painter.state.collectAsState()
if (LocalInspectionMode.current) {
Image(
painter = painter,
contentDescription = null,
)
} else if (state is AsyncImagePainter.State.Success || state is AsyncImagePainter.State.Error) {
Image(
painter = painter,
contentDescription = null,
)
} else {
CircularProgressIndicator()
}
}
Version
coilCompose = "3.2.0"
coilCompose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coilCompose" }
coilNetworkOkhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coilCompose" }
coilSvg = { module = "io.coil-kt.coil3:coil-svg", version.ref = "coilCompose" }