Coil3 with Compose | Issue using rememberAsyncImagePainter with multiple @Preview
#3,001 opened on 2025年5月29日
Repository metrics
- Stars
- (11,779 stars)
- PR merge metrics
- (平均マージ 20h 14m) (30d で 28 merged PRs)
説明
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" }