图片加载:Coil/Kamel
在 Kotlin Multiplatform 项目中,图片加载是常见需求。Coil 3.x 和 Kamel 是两个流行的跨平台图片加载库。
Coil 3.x (推荐)
Coil 3.0+ 提供完整的 KMP 支持,是 Android 平台 Coil 的跨平台版本。
依赖配置
toml
[versions]
coil = "3.0.4"
[libraries]
coil-core = { module = "io.coil-kt.coil3:coil", version.ref = "coil" }
coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" }
coil-network-ktor = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref = "coil" }kotlin
kotlin {
sourceSets {
commonMain.dependencies {
implementation(libs.coil.core)
implementation(libs.coil.compose)
implementation(libs.coil.network.ktor)
}
}
}最新版本查询:https://github.com/coil-kt/coil/releases
Compose 中使用
kotlin
// commonMain
import coil3.compose.AsyncImage
import coil3.compose.LocalPlatformContext
import coil3.request.ImageRequest
import coil3.request.crossfade
@Composable
fun UserAvatar(url: String) {
AsyncImage(
model = ImageRequest.Builder(LocalPlatformContext.current)
.data(url)
.crossfade(true)
.build(),
contentDescription = "User avatar",
modifier = Modifier.size(64.dp)
)
}
// 带占位图和错误图
@Composable
fun ProductImage(url: String) {
AsyncImage(
model = url,
contentDescription = "Product",
placeholder = painterResource(Res.drawable.placeholder),
error = painterResource(Res.drawable.error),
modifier = Modifier.fillMaxWidth()
)
}自定义配置
kotlin
// commonMain
import coil3.ImageLoader
import coil3.PlatformContext
import coil3.disk.DiskCache
import coil3.memory.MemoryCache
import coil3.request.crossfade
import coil3.util.DebugLogger
fun createImageLoader(context: PlatformContext): ImageLoader {
return ImageLoader.Builder(context)
.crossfade(true)
.memoryCache {
MemoryCache.Builder()
.maxSizePercent(context, 0.25)
.build()
}
.diskCache {
DiskCache.Builder()
.directory(getCacheDir(context) / "image_cache")
.maxSizeBytes(512 * 1024 * 1024) // 512 MB
.build()
}
.logger(DebugLogger())
.build()
}Kamel (备选方案)
Kamel 是专为 Compose Multiplatform 设计的图片加载库。
依赖配置
toml
[versions]
kamel = "1.0.0"
[libraries]
kamel-image = { module = "media.kamel:kamel-image", version.ref = "kamel" }基础使用
kotlin
import io.kamel.image.KamelImage
import io.kamel.image.asyncPainterResource
@Composable
fun ImageFromUrl(url: String) {
KamelImage(
resource = asyncPainterResource(url),
contentDescription = "Image",
modifier = Modifier.size(200.dp),
onLoading = {
CircularProgressIndicator(progress = { it })
},
onFailure = { exception ->
Text("Error: ${exception.message}")
}
)
}缓存配置
kotlin
import io.kamel.core.config.KamelConfig
import io.kamel.core.config.takeFrom
import io.kamel.image.config.*
val customKamelConfig = KamelConfig {
takeFrom(KamelConfig.Default)
// 内存缓存
imageBitmapCacheSize = 1000
// 磁盘缓存
fileFetcher()
}
// 使用自定义配置
CompositionLocalProvider(LocalKamelConfig provides customKamelConfig) {
App()
}平台特定实现
expect/actual for Context
kotlin
// commonMain
expect class ImageContext
expect fun getImageContext(): ImageContext
// androidMain
import android.content.Context
actual typealias ImageContext = Context
actual fun getImageContext(): ImageContext {
return AppContext.application
}
// iosMain
actual class ImageContext
actual fun getImageContext(): ImageContext {
return ImageContext()
}图片类型处理
ByteArray 转 ImageBitmap
kotlin
// commonMain
import androidx.compose.ui.graphics.ImageBitmap
expect fun ByteArray.toImageBitmap(): ImageBitmap
// androidMain
import android.graphics.BitmapFactory
import androidx.compose.ui.graphics.asImageBitmap
actual fun ByteArray.toImageBitmap(): ImageBitmap {
return BitmapFactory.decodeByteArray(this, 0, size).asImageBitmap()
}
// iosMain
import androidx.compose.ui.graphics.toComposeImageBitmap
import org.jetbrains.skia.Image
actual fun ByteArray.toImageBitmap(): ImageBitmap {
return Image.makeFromEncoded(this).toComposeImageBitmap()
}最佳实践
✅ 实践 1:预加载图片
kotlin
fun preloadImages(imageLoader: ImageLoader, urls: List<String>) {
urls.forEach { url ->
val request = ImageRequest.Builder(context)
.data(url)
.build()
imageLoader.enqueue(request)
}
}✅ 实践 2:图片压缩
kotlin
val request = ImageRequest.Builder(context)
.data(url)
.size(800, 600) // 限制尺寸
.build()✅ 实践 3:缓存策略
kotlin
// 强制刷新
ImageRequest.Builder(context)
.data(url)
.diskCachePolicy(CachePolicy.WRITE_ONLY)
.memoryCachePolicy(CachePolicy.WRITE_ONLY)
.build()
// 仅使用缓存
ImageRequest.Builder(context)
.data(url)
.diskCachePolicy(CachePolicy.READ_ONLY)
.build()选择 Coil 3.x 还是 Kamel 取决于项目需求。Coil 3.x 生态更成熟,Kamel 更轻量级。