-
Notifications
You must be signed in to change notification settings - Fork 671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid multiple parallel network requests for the same URL #1461
Comments
I agree this would be nice to have. Ideally, Additionally - we can only do this for requests that are going to be written to the disk cache. If they're not being written to the disk cache then we can only read the response body once. There's a few other edge cases that means this would have to be opt-in at least for a while. |
Thinking about this more we should also provide a configurable "keep alive" duration for network requests. That way the user can configure how long to wait before cancelling a network request if there's no more consumer for the result. This would be useful for |
What is the status on this? |
How is the progress on this matter? |
I had the same issue with viewpager of images.. when first image loaded there are 3 requests of the same url.. this is due to the recomposition nature of composes but it can be fixed easily by using remember with imagerequest
|
I tried to fix the issue through an interceptor: /**
* Merge the same requests to avoid multiple parallel network requests for the same URL.
*
* You can set the [mergeFilter] to determine which requests need to be merged,
* the default is to merge the network requests.
*
* You can set the [keyGenerator] to generate the key for the request,
* the default is to use the request data as the key.
*
* Fix the [issue](https://github.com/coil-kt/coil/issues/1461).
*
* @param mergeFilter A function that determines which requests need to be merged.
* @param keyGenerator A function that generates the key for the request.
* @author airsaid
*/
class MergeRequestInterceptor(
private val mergeFilter: (ImageRequest) -> Boolean = {
it.isNetUrlRequest()
},
private val keyGenerator: (ImageRequest) -> String = {
it.generateKey()
}
) : Interceptor {
private val pendingRequests = ConcurrentHashMap<String, CompletableDeferred<ImageResult>>()
override suspend fun intercept(chain: Interceptor.Chain): ImageResult {
val req = chain.request
if (!mergeFilter(req)) {
return chain.proceed(req)
}
// If there is a pending request, we should wait for it
val requestKey = keyGenerator(req)
val existingRequest = pendingRequests[requestKey]
return if (existingRequest != null) {
try {
existingRequest.await()
} catch (ignore: Exception) {
// Ignore the exception to keep the request chain running
}
// We can't return the result of the existing request directly,
// because it will not be shown in the UI for the same result.
// Therefore, we should transfer the request and return a different cached result
chain.proceed(chain.request)
} else {
val deferred = CompletableDeferred<ImageResult>()
pendingRequests[requestKey] = deferred
try {
// Proceed with the actual request
val result = chain.proceed(chain.request)
deferred.complete(result)
result
} catch (e: Exception) {
deferred.completeExceptionally(e)
throw e
} finally {
// Remove the request from the pending map
pendingRequests.remove(requestKey)
}
}
}
}
private fun ImageRequest.isNetUrlRequest(): Boolean {
val data = data
if (data is Uri) {
return data.isNetworkUri
}
if (data is String) {
val uri = Uri.parse(data)
return uri.isNetworkUri
}
return false
}
private fun ImageRequest.generateKey(): String {
return data.toString()
} |
I am developing an application where there can be many identical pictures on one screen (SVG from the server).
When I open the application for the first time, I see multiple parallel requests behind the same picture.
I think it's worth adding a pool of downloads, and if this URL is already being processed, do not make this request again, but wait for the first one to complete and use its result.
The text was updated successfully, but these errors were encountered: