perf(images): coalesce duplicate in-flight Coil network requests

Switch the three image NetworkFetcher sites from
ConcurrentRequestStrategy.UNCOORDINATED to DeDupeConcurrentRequestStrategy,
Coil's coordinated default. UNCOORDINATED let every request hit the
network independently, so the same avatar across many visible feed
notes became N parallel downloads competing for the per-host
dispatcher slots and queueing the genuinely distinct images behind
them. The de-duping strategy lets concurrent requests for a URL share
the first download and then read from disk.

https://claude.ai/code/session_01BeWZGTz48kzURQLTYyN5x9
This commit is contained in:
Claude
2026-05-14 20:51:05 +00:00
parent f2068d6ac3
commit d370c7e40c
3 changed files with 6 additions and 6 deletions
@@ -27,8 +27,8 @@ import coil3.annotation.ExperimentalCoilApi
import coil3.fetch.FetchResult
import coil3.fetch.Fetcher
import coil3.network.CacheStrategy
import coil3.network.ConcurrentRequestStrategy
import coil3.network.ConnectivityChecker
import coil3.network.DeDupeConcurrentRequestStrategy
import coil3.network.NetworkFetcher
import coil3.network.okhttp.asNetworkClient
import coil3.request.Options
@@ -74,7 +74,7 @@ class BlossomFetcher(
diskCache = lazy { imageLoader.diskCache },
cacheStrategy = lazy { CacheStrategy.DEFAULT },
connectivityChecker = lazy { connectivityCheckerLazy.get(options.context) },
concurrentRequestStrategy = lazy { ConcurrentRequestStrategy.UNCOORDINATED },
concurrentRequestStrategy = lazy { DeDupeConcurrentRequestStrategy() },
)
}
}
@@ -33,8 +33,8 @@ import coil3.gif.AnimatedImageDecoder
import coil3.gif.GifDecoder
import coil3.memory.MemoryCache
import coil3.network.CacheStrategy
import coil3.network.ConcurrentRequestStrategy
import coil3.network.ConnectivityChecker
import coil3.network.DeDupeConcurrentRequestStrategy
import coil3.network.NetworkFetcher
import coil3.network.okhttp.asNetworkClient
import coil3.request.Options
@@ -149,7 +149,7 @@ class OkHttpFactory(
diskCache = lazy { imageLoader.diskCache },
cacheStrategy = cacheStrategyLazy,
connectivityChecker = lazy { connectivityCheckerLazy.get(options.context) },
concurrentRequestStrategy = lazy { ConcurrentRequestStrategy.UNCOORDINATED },
concurrentRequestStrategy = lazy { DeDupeConcurrentRequestStrategy() },
)
}
@@ -30,8 +30,8 @@ import coil3.fetch.Fetcher
import coil3.fetch.ImageFetchResult
import coil3.key.Keyer
import coil3.network.CacheStrategy
import coil3.network.ConcurrentRequestStrategy
import coil3.network.ConnectivityChecker
import coil3.network.DeDupeConcurrentRequestStrategy
import coil3.network.NetworkFetcher
import coil3.network.okhttp.asNetworkClient
import coil3.request.Options
@@ -113,7 +113,7 @@ class ProfilePictureFetcher(
diskCache = diskCacheLazy,
cacheStrategy = lazy { CacheStrategy.DEFAULT },
connectivityChecker = lazy { connectivityCheckerLazy.get(options.context) },
concurrentRequestStrategy = lazy { ConcurrentRequestStrategy.UNCOORDINATED },
concurrentRequestStrategy = lazy { DeDupeConcurrentRequestStrategy() },
)
return ProfilePictureFetcher(