coil-kt / coil

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

Coil disk cache doesn't work when loading an icon file manually #2430

Closed Shinokuni closed 3 months ago

Shinokuni commented 3 months ago

Describe the bug Loading in disk cache a base64 icon manually fails. I am getting a base64 icon from an API json file I would like to put in cache with a key to be able to load it later.

val imageLoader = context.imageLoader

val request = ImageRequest.Builder(context)
    .diskCacheKey(DISK_CACHE_KEY)
    .data(loadIconByteArray(context))
    .build()

imageLoader.execute(request)

...

AsyncImage(
    model = DISK_CACHE_KEY,
    contentDescription = null,
    modifier = Modifier.size(24.dp)
)

On the other hand, the exact same code with memory cache works:

val imageLoader = context.imageLoader

val request = ImageRequest.Builder(context)
    .memoryCacheKey(MEMORY_KEY)
    .data(loadIconByteArray(context))
    .build()

imageLoader.execute(request)

...

AsyncImage(
    model = MEMORY_KEY,
    contentDescription = null,
    modifier = Modifier.size(24.dp)
)

ImageLoader configuration:

override fun newImageLoader(): ImageLoader {
    return ImageLoader.Builder(this)
        .memoryCachePolicy(CachePolicy.ENABLED)
        .diskCachePolicy(CachePolicy.ENABLED)
        .diskCache {
            DiskCache.Builder()
               .directory(this.cacheDir.resolve("image_cache"))
               .maximumMaxSizeBytes(104900000) // 100 MB
               .build()
      }
         .crossfade(true)
         .build()
}

Am I missing something, like an expected different behavior depending on cache type?

To Reproduce I did a little sample project to reproduce the issue.

Version Coil 2.7.0 Compose 2024.04.01/2024.06.00

colinrtwhite commented 3 months ago

Thanks for the repro project. Passing the memory cache and disk cache key directly to the AsyncImage model isn't supported. I'm not sure why the memory cache key case is working, but it's not intended. Coil's DiskCache isn't queried automatically - a Fetcher has to use it. Currently only the OkHttpFetcher uses it so only URLs will be disk cached.

Based on your use case I'd look into creating a custom Fetcher so you can pass it a URI (or something similar) and either read it from the disk cache or load the data using loadIconByteArray. Alternatively you could read and write your data directly using DiskCache's openSnapshot/openEditor. If you pass a ByteArray as the AsyncImage(model = that is supported.