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.
This commit is contained in:
parent
7c09c6aa2b
commit
12040b90fb
|
@ -5,6 +5,7 @@ import com.bumptech.glide.load.DataSource
|
||||||
import com.bumptech.glide.load.engine.GlideException
|
import com.bumptech.glide.load.engine.GlideException
|
||||||
import com.bumptech.glide.request.RequestListener
|
import com.bumptech.glide.request.RequestListener
|
||||||
import com.bumptech.glide.request.target.Target
|
import com.bumptech.glide.request.target.Target
|
||||||
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlin.coroutines.resumeWithException
|
import kotlin.coroutines.resumeWithException
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
@ -17,15 +18,25 @@ suspend fun <R> RequestBuilder<R>.submitAsync(
|
||||||
height: Int = Target.SIZE_ORIGINAL
|
height: Int = Target.SIZE_ORIGINAL
|
||||||
): R {
|
): R {
|
||||||
return suspendCancellableCoroutine { continuation ->
|
return suspendCancellableCoroutine { continuation ->
|
||||||
val target = addListener(
|
val target = addListener(ContinuationRequestListener(continuation))
|
||||||
object : RequestListener<R> {
|
.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(
|
override fun onLoadFailed(
|
||||||
e: GlideException?,
|
e: GlideException?,
|
||||||
model: Any?,
|
model: Any?,
|
||||||
target: Target<R>,
|
target: Target<R>,
|
||||||
isFirstResource: Boolean
|
isFirstResource: Boolean
|
||||||
): Boolean {
|
): Boolean {
|
||||||
continuation.resumeWithException(e ?: GlideException("Image loading failed"))
|
continuation?.let {
|
||||||
|
continuation = null
|
||||||
|
it.resumeWithException(e ?: GlideException("Image loading failed"))
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,13 +47,12 @@ suspend fun <R> RequestBuilder<R>.submitAsync(
|
||||||
dataSource: DataSource,
|
dataSource: DataSource,
|
||||||
isFirstResource: Boolean
|
isFirstResource: Boolean
|
||||||
): Boolean {
|
): Boolean {
|
||||||
|
continuation?.let {
|
||||||
if (target?.request?.isComplete == true) {
|
if (target?.request?.isComplete == true) {
|
||||||
continuation.resume(resource)
|
continuation = null
|
||||||
|
it.resume(resource)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).submit(width, height)
|
|
||||||
continuation.invokeOnCancellation { target.cancel(true) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue