Coil image caching not working with Jetpack Compose
Asked Answered
C

2

12

I am using coil(version 2.1.0) to load images from URL. When there is network connection, the images are loading fine. However, when there is no network connection, the images are not being pulled from the cache as I expected them. Here's a block of code I have.

class App : Application(), ImageLoaderFactory {

    override fun newImageLoader(): ImageLoader {
       return ImageLoader.Builder(this)
            .memoryCache {
                MemoryCache.Builder(this)
                    .maxSizePercent(0.25)
                    .build()
            }
            .diskCache {
                DiskCache.Builder()
                    .directory(cacheDir.resolve("image_cache"))
                    .maxSizeBytes(5 * 1024 * 1024)
                    .build()
            }
            .build()
    }
  }

In Compose:

                val context = LocalContext.current
                val placeholderImage = R.drawable.ic_placeholder
    
                val imageRequest = ImageRequest.Builder(context)
                    .data(imageUrl)
                    .memoryCacheKey(imageUrl)
                    .diskCacheKey(imageUrl)
                    .placeholder(placeholderImage)
                    .error(placeholderImage)
                    .fallback(placeholderImage)
                    .diskCachePolicy(CachePolicy.ENABLED)
                    .memoryCachePolicy(CachePolicy.ENABLED)
                    .transformations(CircleCropTransformation())
                    .build()

                AsyncImage(
                    model = imageRequest,
                    modifier = Modifier.size(64.dp),
                    contentDescription = null,
                    imageLoader = context.imageLoader
                )

When the device is offline, it only loads the placeholder image instead of the image from cache as expected. What am I missing here?

Cosmorama answered 14/7, 2022 at 14:10 Comment(1)
Do not use cacheDir.resolve but use filesDir.resolve Check this ticket for more info: github.com/coil-kt/coil/issues/1447Chlorite
C
17

I used logger(DebugLogger()) in ImageLoader to figure out what was going on and I found out that app was running into HTTP 504 error when Coil was trying to load image offline. So I added .respectCacheHeaders(false) to the ImageLoader. That seemed to do the trick for me.

Hope this helps someone else running into similar problem.

Cosmorama answered 15/7, 2022 at 17:51 Comment(2)
What does this look like in code?Ethelred
@Ethelred val imageLoader = ImageLoader.Builder(context).components { add(ImageDecoderDecoder.Factory()) }.respectCacheHeaders(false).build() then pass it to an Image like this Image(painter = rememberAsyncImagePainter(imageRequest, imageLoader = imageLoader), contentDescription = null)Bacteriostat
W
1

coil will decide if disk caching is required based on the Cache-Control field in the http header.

Here is the change log of coil 2.0.0.

  • New: Introduce a public DiskCache API.
    • Use ImageLoader.Builder.diskCache and DiskCache.Builder to configure the disk cache.
    • You should not use OkHttp's Cache with Coil 2.0. See here for more info.
    • Cache-Control and other cache headers are still supported - except Vary headers, as the cache only checks that the URLs match. Additionally, only responses with a response code in the range [200..300) are cached.
    • Existing disk caches will be cleared when upgrading to 2.0.

If you need to force caching, see https://coil-kt.github.io/coil/recipes/#headers. And I think it would be better to use addHeader to avoid dropping other http header fields.

Weinshienk answered 15/7, 2022 at 1:26 Comment(5)
I don't think that's the case. The change log says that cache headers are still supported, it doesn't say the automatic caching without it is being dumped. That would be really stupid imo if the library forced user to add headers on http level to use its core functionalityArmillia
I agree that for coil2.0. such an api is strange, but at least in my project I need the cache control field.Weinshienk
Maybe it's just a bug since on official cache docs: coil-kt.github.io/coil/image_loaders/#caching there is nothing about cache-control headers requirementArmillia
I remember before 2.0, this page didn't mention this. I don't think it's a bug. Respecting the http header is a reasonable design. Perhaps it would be better for Coil to provide an alias for addHeader("Cache-Control", ...) . Anyway, at least you can try it to see if it works.Weinshienk
With 2.x, OkHttp's cache will not be used by Coil since it implements its own disk cache. coil-kt.github.io/coil/upgrading/#disk-cache I found a workaround for my case, which I have posted below as an answer.Cosmorama

© 2022 - 2024 — McMap. All rights reserved.