From 6540b6776913af9ac020e61e50a47ed67874c074 Mon Sep 17 00:00:00 2001 From: Colin White Date: Mon, 27 Jan 2025 17:32:38 -0800 Subject: [PATCH 1/2] Add ImageLoader option for creating memory cache key using toString() by default. --- .../kotlin/coil3/RealImageLoader.android.kt | 7 ++++ .../kotlin/coil3/RealImageLoader.kt | 33 +++++++++++-------- .../commonMain/kotlin/coil3/imageLoaders.kt | 18 ++++++++++ .../commonMain/kotlin/coil3/key/AnyKeyer.kt | 21 ++++++++++++ 4 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 coil-core/src/commonMain/kotlin/coil3/key/AnyKeyer.kt diff --git a/coil-core/src/androidMain/kotlin/coil3/RealImageLoader.android.kt b/coil-core/src/androidMain/kotlin/coil3/RealImageLoader.android.kt index d0fdfe0ff9..d5f12295ce 100644 --- a/coil-core/src/androidMain/kotlin/coil3/RealImageLoader.android.kt +++ b/coil-core/src/androidMain/kotlin/coil3/RealImageLoader.android.kt @@ -1,5 +1,7 @@ package coil3 +import android.graphics.Bitmap +import android.graphics.drawable.Drawable import android.os.Build.VERSION.SDK_INT import coil3.decode.BitmapFactoryDecoder import coil3.decode.ExifOrientationStrategy.Companion.RESPECT_ALL @@ -11,6 +13,7 @@ import coil3.fetch.ContentUriFetcher import coil3.fetch.DrawableFetcher import coil3.fetch.ResourceUriFetcher import coil3.key.AndroidResourceUriKeyer +import coil3.key.CacheDisabledKeyer import coil3.map.AndroidUriMapper import coil3.map.ResourceIntMapper import coil3.request.Disposable @@ -79,6 +82,10 @@ internal actual fun ComponentRegistry.Builder.addAndroidComponents( // Keyers add(AndroidResourceUriKeyer()) + if (options.defaultKeyerEnabled) { + add(CacheDisabledKeyer()) + add(CacheDisabledKeyer()) + } // Fetchers add(AssetUriFetcher.Factory()) diff --git a/coil-core/src/commonMain/kotlin/coil3/RealImageLoader.kt b/coil-core/src/commonMain/kotlin/coil3/RealImageLoader.kt index 8be04286b2..cd3009adca 100644 --- a/coil-core/src/commonMain/kotlin/coil3/RealImageLoader.kt +++ b/coil-core/src/commonMain/kotlin/coil3/RealImageLoader.kt @@ -6,6 +6,7 @@ import coil3.fetch.DataUriFetcher import coil3.fetch.FileUriFetcher import coil3.intercept.EngineInterceptor import coil3.intercept.RealInterceptorChain +import coil3.key.CacheEnabledKeyer import coil3.key.FileUriKeyer import coil3.key.UriKeyer import coil3.map.PathMapper @@ -56,7 +57,7 @@ internal class RealImageLoader( .addAndroidComponents(options) .addJvmComponents(options) .addAppleComponents(options) - .addCommonComponents() + .addCommonComponents(options) .add(EngineInterceptor(this, systemCallbacks, requestService, options.logger)) .build() private val shutdown = atomic(false) @@ -288,18 +289,24 @@ internal expect fun ComponentRegistry.Builder.addAppleComponents( options: RealImageLoader.Options, ): ComponentRegistry.Builder -internal fun ComponentRegistry.Builder.addCommonComponents(): ComponentRegistry.Builder { - return this - // Mappers - .add(StringMapper()) - .add(PathMapper()) - // Keyers - .add(FileUriKeyer()) - .add(UriKeyer()) - // Fetchers - .add(FileUriFetcher.Factory()) - .add(ByteArrayFetcher.Factory()) - .add(DataUriFetcher.Factory()) +internal fun ComponentRegistry.Builder.addCommonComponents( + options: RealImageLoader.Options, +): ComponentRegistry.Builder = apply { + // Mappers + add(StringMapper()) + add(PathMapper()) + + // Keyers + add(FileUriKeyer()) + add(UriKeyer()) + if (options.defaultKeyerEnabled) { + add(CacheEnabledKeyer()) + } + + // Fetchers + add(FileUriFetcher.Factory()) + add(ByteArrayFetcher.Factory()) + add(DataUriFetcher.Factory()) } private const val TAG = "RealImageLoader" diff --git a/coil-core/src/commonMain/kotlin/coil3/imageLoaders.kt b/coil-core/src/commonMain/kotlin/coil3/imageLoaders.kt index 7410398896..b3aa6d71d3 100644 --- a/coil-core/src/commonMain/kotlin/coil3/imageLoaders.kt +++ b/coil-core/src/commonMain/kotlin/coil3/imageLoaders.kt @@ -1,5 +1,7 @@ package coil3 +import coil3.key.Keyer + /** * Create a new [ImageLoader] without configuration. */ @@ -30,3 +32,19 @@ internal val RealImageLoader.Options.serviceLoaderEnabled: Boolean private val serviceLoaderEnabledKey = Extras.Key(default = true) // endregion + +/** + * Enables the default [Keyer]. This means that data types that don't have a registered [Keyer] + * will have a memory cache key created for them using [Any.toString]. + * + * If disabled (the default), images will not be cached if they do not have a registered [Keyer] + * for the associated data type. + */ +fun ImageLoader.Builder.defaultKeyerEnabled(enable: Boolean) = apply { + extras[defaultKeyerEnabledKey] = enable +} + +internal val RealImageLoader.Options.defaultKeyerEnabled: Boolean + get() = defaults.extras.getOrDefault(defaultKeyerEnabledKey) + +private val defaultKeyerEnabledKey = Extras.Key(default = false) diff --git a/coil-core/src/commonMain/kotlin/coil3/key/AnyKeyer.kt b/coil-core/src/commonMain/kotlin/coil3/key/AnyKeyer.kt new file mode 100644 index 0000000000..03ef591887 --- /dev/null +++ b/coil-core/src/commonMain/kotlin/coil3/key/AnyKeyer.kt @@ -0,0 +1,21 @@ +package coil3.key + +import coil3.request.Options + +@Suppress("UNCHECKED_CAST") +internal fun CacheEnabledKeyer(): Keyer = CacheEnabledKeyer as Keyer + +private object CacheEnabledKeyer : Keyer { + override fun key(data: Any, options: Options): String { + return data.toString() + } +} + +@Suppress("UNCHECKED_CAST") +internal fun CacheDisabledKeyer(): Keyer = CacheDisabledKeyer as Keyer + +private object CacheDisabledKeyer : Keyer { + override fun key(data: Any, options: Options): String? { + return null + } +} From 91f1a4da1899b75dab41dfcc34d8286af538af22 Mon Sep 17 00:00:00 2001 From: Colin White Date: Mon, 27 Jan 2025 17:50:39 -0800 Subject: [PATCH 2/2] Update API. --- coil-core/api/android/coil-core.api | 1 + coil-core/api/coil-core.klib.api | 1 + coil-core/api/jvm/coil-core.api | 1 + 3 files changed, 3 insertions(+) diff --git a/coil-core/api/android/coil-core.api b/coil-core/api/android/coil-core.api index cc21416bad..170e8dcb13 100644 --- a/coil-core/api/android/coil-core.api +++ b/coil-core/api/android/coil-core.api @@ -209,6 +209,7 @@ public final class coil3/ImageLoader$Builder { public final class coil3/ImageLoadersKt { public static final fun ImageLoader (Landroid/content/Context;)Lcoil3/ImageLoader; + public static final fun defaultKeyerEnabled (Lcoil3/ImageLoader$Builder;Z)Lcoil3/ImageLoader$Builder; public static final fun serviceLoaderEnabled (Lcoil3/ImageLoader$Builder;Z)Lcoil3/ImageLoader$Builder; } diff --git a/coil-core/api/coil-core.klib.api b/coil-core/api/coil-core.klib.api index 762882a339..92d65e58e8 100644 --- a/coil-core/api/coil-core.klib.api +++ b/coil-core/api/coil-core.klib.api @@ -1031,6 +1031,7 @@ final fun (coil3/ImageLoader.Builder).coil3.request/allowConversionToBitmap(kotl final fun (coil3/ImageLoader.Builder).coil3.request/crossfade(kotlin/Boolean): coil3/ImageLoader.Builder // coil3.request/crossfade|crossfade@coil3.ImageLoader.Builder(kotlin.Boolean){}[0] final fun (coil3/ImageLoader.Builder).coil3.request/crossfade(kotlin/Int): coil3/ImageLoader.Builder // coil3.request/crossfade|crossfade@coil3.ImageLoader.Builder(kotlin.Int){}[0] final fun (coil3/ImageLoader.Builder).coil3.request/maxBitmapSize(coil3.size/Size): coil3/ImageLoader.Builder // coil3.request/maxBitmapSize|maxBitmapSize@coil3.ImageLoader.Builder(coil3.size.Size){}[0] +final fun (coil3/ImageLoader.Builder).coil3/defaultKeyerEnabled(kotlin/Boolean): coil3/ImageLoader.Builder // coil3/defaultKeyerEnabled|defaultKeyerEnabled@coil3.ImageLoader.Builder(kotlin.Boolean){}[0] final fun (coil3/ImageLoader.Builder).coil3/serviceLoaderEnabled(kotlin/Boolean): coil3/ImageLoader.Builder // coil3/serviceLoaderEnabled|serviceLoaderEnabled@coil3.ImageLoader.Builder(kotlin.Boolean){}[0] final fun (kotlin/String).coil3/toUri(kotlin/String = ...): coil3/Uri // coil3/toUri|toUri@kotlin.String(kotlin.String){}[0] final fun (org.jetbrains.skia/Bitmap).coil3/asImage(kotlin/Boolean = ...): coil3/BitmapImage // coil3/asImage|asImage@org.jetbrains.skia.Bitmap(kotlin.Boolean){}[0] diff --git a/coil-core/api/jvm/coil-core.api b/coil-core/api/jvm/coil-core.api index cd7cfec1dd..4d1ac686ff 100644 --- a/coil-core/api/jvm/coil-core.api +++ b/coil-core/api/jvm/coil-core.api @@ -183,6 +183,7 @@ public final class coil3/ImageLoader$Builder { public final class coil3/ImageLoadersKt { public static final fun ImageLoader (Lcoil3/PlatformContext;)Lcoil3/ImageLoader; + public static final fun defaultKeyerEnabled (Lcoil3/ImageLoader$Builder;Z)Lcoil3/ImageLoader$Builder; public static final fun serviceLoaderEnabled (Lcoil3/ImageLoader$Builder;Z)Lcoil3/ImageLoader$Builder; }