diff --git a/coil-core/src/commonMain/kotlin/coil3/ComponentRegistry.kt b/coil-core/src/commonMain/kotlin/coil3/ComponentRegistry.kt index 71a4f7b827..da42071c72 100644 --- a/coil-core/src/commonMain/kotlin/coil3/ComponentRegistry.kt +++ b/coil-core/src/commonMain/kotlin/coil3/ComponentRegistry.kt @@ -118,7 +118,6 @@ class ComponentRegistry private constructor( fun newBuilder() = Builder(this) class Builder { - internal val interceptors: MutableList<Interceptor> internal val mappers: MutableList<Pair<Mapper<out Any, *>, KClass<out Any>>> internal val keyers: MutableList<Pair<Keyer<out Any>, KClass<out Any>>> diff --git a/coil-core/src/commonMain/kotlin/coil3/memory/MemoryCacheService.kt b/coil-core/src/commonMain/kotlin/coil3/memory/MemoryCacheService.kt index 6276284411..153260e9ad 100644 --- a/coil-core/src/commonMain/kotlin/coil3/memory/MemoryCacheService.kt +++ b/coil-core/src/commonMain/kotlin/coil3/memory/MemoryCacheService.kt @@ -20,6 +20,7 @@ import coil3.size.isOriginal import coil3.size.pxOrElse import coil3.util.Logger import coil3.util.isPlaceholderCached +import coil3.util.key import coil3.util.log import kotlin.math.abs @@ -43,7 +44,7 @@ internal class MemoryCacheService( // Slow path: create a new memory cache key. eventListener.keyStart(request, mappedData) - val key = imageLoader.components.key(mappedData, options) + val key = imageLoader.components.key(mappedData, options, logger, TAG) eventListener.keyEnd(request, key) if (key == null) { return null diff --git a/coil-core/src/commonMain/kotlin/coil3/util/utils.kt b/coil-core/src/commonMain/kotlin/coil3/util/utils.kt index 8dd4a6f783..36360da560 100644 --- a/coil-core/src/commonMain/kotlin/coil3/util/utils.kt +++ b/coil-core/src/commonMain/kotlin/coil3/util/utils.kt @@ -9,9 +9,11 @@ import coil3.decode.Decoder import coil3.fetch.Fetcher import coil3.intercept.Interceptor import coil3.intercept.RealInterceptorChain +import coil3.key.Keyer import coil3.request.ErrorResult import coil3.request.ImageRequest import coil3.request.NullRequestDataException +import coil3.request.Options import kotlin.coroutines.CoroutineContext import kotlin.experimental.ExperimentalNativeApi import kotlin.reflect.KClass @@ -46,6 +48,31 @@ internal fun AutoCloseable.closeQuietly() { internal val EMPTY_IMAGE_FACTORY: (ImageRequest) -> Image? = { null } +/** Same as [ComponentRegistry.key], but with extra logging. */ +@Suppress("UNCHECKED_CAST") +internal fun ComponentRegistry.key( + data: Any, + options: Options, + logger: Logger?, + tag: String, +): String? { + var hasKeyerForType = false + keyers.forEachIndices { (keyer, type) -> + if (type.isInstance(data)) { + hasKeyerForType = true + (keyer as Keyer<Any>).key(data, options)?.let { return it } + } + } + if (!hasKeyerForType) { + logger?.log(tag, Logger.Level.Warn) { + "No keyer is registered for data with type '${data::class.simpleName}'. " + + "Register Keyer<${data::class.simpleName}> in the component registry to " + + "cache the output image in the memory cache." + } + } + return null +} + internal fun ComponentRegistry.Builder.addFirst( pair: Pair<Fetcher.Factory<*>, KClass<*>>? ) = apply { if (pair != null) lazyFetcherFactories.add(0) { listOf(pair) } }