coil-kt / coil

Image loading for Android and Compose Multiplatform.
https://coil-kt.github.io/coil/
Apache License 2.0
10.83k stars 664 forks source link

Consider supporting a flag to move the memory cache check ahead of the interceptor chain. #2670

Open colinrtwhite opened 1 week ago

colinrtwhite commented 1 week ago

Is your feature request related to a problem? Please describe. There's been some appetite to perform the memory cache check ahead of the interceptor chain. This is a relatively big behaviour change, but it has a couple benefits:

Describe the solution you'd like Add an opt in flag to ImageLoader and ImageRequest to perform the mapping, keying, and memory cache check here instead of here.

We'll still need to preserve the option to intercept before the memory cache check as some users might want that.

colinrtwhite commented 6 days ago

Took a spike at using launch(start = CoroutineStart.UNDISPATCHED) instead of Dispatchers.Main.immedate and UNDISPATCHED still causes us to dispatch as we only avoid dispatching "until the next suspension", which is imageLoader.execute. This means we likely need to keep Dispatchers.Main.immedate.

Why don't we perform the memory cache check before calling imageLoader.execute?

  1. This would require exposing a lot of internal Coil logic to call inside AsyncImagePainter. We also then have two places we're checking the memory cache which complicates the design.
  2. This isn't possible as Coil requires a size to compute the MemoryCache.Key and SizeResolver.size is a suspending function, which means launch(start = CoroutineStart.UNDISPATCHED) still wouldn't work.

Screen_recording_20241115_183033.webm

zach-klippenstein commented 3 days ago

What does imageLoader.execute actually do asynchronously in the fast path (memory cache hit)?

One idea: use a custom dispatcher, similar to the one Compose uses, that drains the queue right before drawing. This dispatcher would only be used for Coil's own coroutine loading calls, so on most frames the pre-draw drain would be a no-op and on frames where there is work, it would only be image-related work.

Pros:

Cons: