coil-kt/coil

Coil3 with Compose | Issue using rememberAsyncImagePainter with multiple @Preview

Open

#3001 opened on May 29, 2025

View on GitHub
 (4 comments) (0 reactions) (0 assignees)Kotlin (11,779 stars) (757 forks)batch import
help wanted

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.

Image

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" }

Contributor guide