chinwag-android/app/src/main/java/com/keylesspalace/tusky/util/GlideExtensions.kt
Christophe Beyls 12040b90fb
fix: RequestBuilder.submitAsync() throwing an Exception if the Glide request is restarted (#4569)
This is the third attempt to fix `RequestBuilder.submitAsync()`. For the
rationale, see the comments of #4436.

We now clear the continuation reference after resuming it, to make sure
that:
1) It will only be resumed once
2) It will not leak the coroutine when Glide keeps the `Request` around.
2024-07-14 09:01:01 +02:00

58 lines
1.8 KiB
Kotlin

package com.keylesspalace.tusky.util
import com.bumptech.glide.RequestBuilder
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 kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlinx.coroutines.suspendCancellableCoroutine
/**
* Allows waiting for a Glide request to complete without blocking a background thread.
*/
suspend fun <R> RequestBuilder<R>.submitAsync(
width: Int = Target.SIZE_ORIGINAL,
height: Int = Target.SIZE_ORIGINAL
): R {
return suspendCancellableCoroutine { continuation ->
val target = addListener(ContinuationRequestListener(continuation))
.submit(width, height)
continuation.invokeOnCancellation { target.cancel(true) }
}
}
private class ContinuationRequestListener<R>(continuation: Continuation<R>) : RequestListener<R> {
private var continuation: Continuation<R>? = continuation
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<R>,
isFirstResource: Boolean
): Boolean {
continuation?.let {
continuation = null
it.resumeWithException(e ?: GlideException("Image loading failed"))
}
return false
}
override fun onResourceReady(
resource: R & Any,
model: Any,
target: Target<R>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
continuation?.let {
if (target?.request?.isComplete == true) {
continuation = null
it.resume(resource)
}
}
return false
}
}