saket / telephoto

Building blocks for designing media experiences in Compose UI
https://saket.github.io/telephoto/
Apache License 2.0
958 stars 30 forks source link

Coil returned an image that is missing from its disk cache #106

Open latsson opened 4 days ago

latsson commented 4 days ago

Hey!

Thanks for a really nice library. This is the only one I found in Compose that keeps the quality of the image while zooming.

When rolling this out in a large app we have noticed a bunch of crashes. This seems to happen for all devices on all OS versions. No idea how to reproduce it though.

Fatal Exception: java.lang.IllegalStateException: Coil returned an image that is missing from its disk cache
       at me.saket.telephoto.zoomable.coil.Resolver.toSubSamplingImageSource(CoilImageSource.kt:187)
       at me.saket.telephoto.zoomable.coil.Resolver.access$toSubSamplingImageSource(CoilImageSource.kt)
       at me.saket.telephoto.zoomable.coil.Resolver$toSubSamplingImageSource$1.invokeSuspend(CoilImageSource.kt:12)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
       at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:101)
       at android.os.Handler.handleCallback(Handler.java:958)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loopOnce(Looper.java:230)
       at android.os.Looper.loop(Looper.java:319)
       at android.app.ActivityThread.main(ActivityThread.java:8919)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)

My code (inside a HorizontalPager)

val zoomState = rememberZoomableImageState(
    zoomableState = rememberZoomableState(
        zoomSpec = ZoomSpec(maxZoomFactor = 3f),
    ),
)

ZoomableAsyncImage(
    model = mediaItem.url,
    contentDescription = mediaItem.altText,
    state = zoomState,
)

Version used: telephotoZoomableImageCoil = { module = "me.saket.telephoto:zoomable-image-coil", version = "0.13.0" }

saket commented 4 days ago

Hmm it's weird that coil is returning a null entry from its disk cache despite reporting a non-null disk cache key. https://github.com/saket/telephoto/blob/dd794df0fb8a007d8e92abab9707bb54071e592b/zoomable-image/coil/src/main/kotlin/me/saket/telephoto/zoomable/coil/CoilImageSource.kt#L181-L189

@latsson Are there any other useful breadcrumbs left by your error reporting service?

saket commented 4 days ago

@colinrtwhite are there any other edge cases related to disk caching that I might be missing?

This is probably another example of why I wish Coil had a public API for downloading images to disk.

latsson commented 4 days ago

Hmm it's weird that coil is returning a null entry from its disk cache despite reporting a non-null disk cache key.

https://github.com/saket/telephoto/blob/dd794df0fb8a007d8e92abab9707bb54071e592b/zoomable-image/coil/src/main/kotlin/me/saket/telephoto/zoomable/coil/CoilImageSource.kt#L181-L189

@latsson Are there any other useful breadcrumbs left by your error reporting service?

Sadly nothing other of interest 😐 It's just twice as common as the other 2 I wrote about.

colinrtwhite commented 3 days ago

@saket I think there's a couple potential cases where result.diskCacheKey could be non-null by the time openSnapshot is called:

I think what Telefoto is looking for is an atomic API that writes the image data to disk then immediately opens a source for the file. That way we avoid the race condition between writing the image data and calling openSnapshot.

Could you open a feature request on Coil's tracker so we can track? 🙏🏻