diff --git a/integration/compose/src/androidTest/java/com/bumptech/glide/integration/compose/GlideImageTest.kt b/integration/compose/src/androidTest/java/com/bumptech/glide/integration/compose/GlideImageTest.kt index f8c727e362..2080fa7cfa 100644 --- a/integration/compose/src/androidTest/java/com/bumptech/glide/integration/compose/GlideImageTest.kt +++ b/integration/compose/src/androidTest/java/com/bumptech/glide/integration/compose/GlideImageTest.kt @@ -28,6 +28,12 @@ import com.bumptech.glide.integration.compose.test.expectDisplayedDrawable import com.bumptech.glide.integration.compose.test.expectDisplayedDrawableSize import com.bumptech.glide.integration.ktx.InternalGlideApi import com.bumptech.glide.integration.ktx.Size +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.google.common.truth.Truth.assertThat +import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicReference import org.junit.Rule import org.junit.Test @@ -281,4 +287,40 @@ class GlideImageTest { expectDisplayedDrawableSize(Size(expectedSize.dpToPixels(), expectedSize.dpToPixels())) ) } + + @Test + fun glideImage_withSuccessfulResource_callsOnResourceReadyOnce() { + val onResourceReadyCounter = AtomicInteger() + val requestListener = object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean, + ): Boolean { + throw UnsupportedOperationException() + } + + override fun onResourceReady( + resource: Drawable?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean, + ): Boolean { + onResourceReadyCounter.incrementAndGet() + return false + } + } + + glideComposeRule.setContent { + GlideImage(model = android.R.drawable.star_big_on, contentDescription = "") { + it.listener(requestListener) + } + } + + glideComposeRule.waitForIdle() + + assertThat(onResourceReadyCounter.get()).isEqualTo(1) + } } diff --git a/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlidePainter.kt b/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlidePainter.kt index 37f9a5bc85..5c1cf28436 100644 --- a/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlidePainter.kt +++ b/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlidePainter.kt @@ -3,6 +3,7 @@ package com.bumptech.glide.integration.compose import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable +import android.util.Log import androidx.compose.runtime.MutableState import androidx.compose.runtime.RememberObserver import androidx.compose.runtime.Stable @@ -29,6 +30,7 @@ import com.bumptech.glide.integration.ktx.flowResolvable import com.google.accompanist.drawablepainter.DrawablePainter import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.job import kotlinx.coroutines.launch @@ -52,6 +54,7 @@ constructor( private var delegate: Painter? by mutableStateOf(null) private val scope = scope + SupervisorJob(parent = scope.coroutineContext.job) + Dispatchers.Main.immediate + private var currentJob: Job? = null override val intrinsicSize: Size get() = delegate?.intrinsicSize ?: Size.Unspecified @@ -66,25 +69,27 @@ constructor( override fun onForgotten() { (delegate as? RememberObserver)?.onForgotten() + currentJob?.cancel() + currentJob = null } override fun onRemembered() { (delegate as? RememberObserver)?.onRemembered() - launchRequest() + if (currentJob == null) { + currentJob = launchRequest() + } } @OptIn(ExperimentGlideFlows::class, InternalGlideApi::class) - private fun launchRequest() { - this.scope.launch { - requestBuilder.flowResolvable(size).collect { - updateDelegate( - when (it) { - is Resource -> it.resource - is Placeholder -> it.placeholder - } - ) - status = it.status - } + private fun launchRequest() = this.scope.launch { + requestBuilder.flowResolvable(size).collect { + updateDelegate( + when (it) { + is Resource -> it.resource + is Placeholder -> it.placeholder + } + ) + status = it.status } }