Kotlin异步图像加载库Coil未能正确缓存图像,每次都需要重新加载。

4
我正在使用Coil依赖项,以便我可以利用AsyncImage
这是我展示图片的方式:
    AsyncImage(
        model = ImageRequest.Builder(LocalContext.current)
            .data(img)
            .crossfade(true)
            .memoryCachePolicy(
                CachePolicy.ENABLED)
            .build(),
        placeholder = painterResource(R.drawable.default_profile_picture),
        contentDescription = "Profile Picture",
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .clip(RoundedCornerShape(100.dp))
            .size(100.dp)
    )

我遇到的问题是缓存。我原以为每次下载图片时,它都会被缓存,当应用程序打开时,它会简单地显示!然而,每次我启动应用程序时,我都会看到占位符一小段时间,然后再次下载图片。我是否使用 AsyncImage 不正确?
更新 我已经更新了如何使用 AsyncImage,我在 ComponentActivity() 类中使用了一个 imageLoader,上下文为 applicationContext:
override fun newImageLoader(): ImageLoader = ImageLoader.Builder(applicationContext)
        .diskCache {
            DiskCache.Builder()
                .directory(applicationContext.cacheDir.resolve("image_cache"))
                .maxSizePercent(0.25)
                .build()
        }
        .networkCachePolicy(CachePolicy.ENABLED)
        .diskCachePolicy(CachePolicy.ENABLED)
        .respectCacheHeaders(false)
        .addLastModifiedToFileCacheKey(true)
        .build()

这是在我的@Composable中

         val request: ImageRequest = ImageRequest.Builder(LocalContext.current.applicationContext)
                .data(profile.value?.img)
                .crossfade(true)
                .diskCacheKey(profile.value?.img)
                .build()

            LocalContext.current.applicationContext.imageLoader.enqueue(request)

            AsyncImage(
                model = request,
                placeholder = painterResource(R.drawable.default_profile_picture),
                contentDescription = "Profile Picture",
                contentScale = ContentScale.Crop,
                modifier = Modifier
                    .clip(RoundedCornerShape(100.dp))
                    .size(50.dp)
            )

然而,似乎图片加载的时间更长了?我甚至添加了期望它们保存的确切diskCacheKey。

请问有人能告诉我哪里做错了吗?

更新2

这是我的更新后的ImageLoader

 override fun newImageLoader(): ImageLoader = ImageLoader.Builder(applicationContext)
        .diskCache {
            DiskCache.Builder()
                .directory(applicationContext.cacheDir.resolve("image_cache"))
                .maxSizePercent(0.25)
                .build()
        }
        .networkCachePolicy(CachePolicy.ENABLED)
        .diskCachePolicy(CachePolicy.ENABLED)
        .respectCacheHeaders(true)
        .build()

这是我如何显示图片的方法:

val request: ImageRequest = ImageRequest.Builder(LocalContext.current.applicationContext)
   .data(space.img)
   .crossfade(true)
   .diskCacheKey(space.img)
   .diskCachePolicy(CachePolicy.ENABLED)
   .setHeader("Cache-Control", "max-age=31536000")
   .build()


AsyncImage(
   model = request,
   placeholder = painterResource(R.drawable.default_space_picture),
   contentDescription = "Space Picture",
   contentScale = ContentScale.Crop,
   modifier = Modifier
       .clip(RoundedCornerShape(100.dp))
       .size(50.dp)
)

当我尝试执行以下操作时:

SubcomposeAsyncImage(
    model = request,
    contentDescription = "Profile Picture",
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .clip(RoundedCornerShape(100.dp))
        .size(50.dp)
) {
    val state = painter.state
    if (state is AsyncImagePainter.State.Success) {
        SubcomposeAsyncImageContent()
        LaunchedEffect(Unit) {
            Log.d("DATASOURCE", state.result.dataSource.toString())
            println(context.imageLoader.diskCache?.get(space.img)?.data)
        }
    }
}

我理解到这个问题是这样的:
2022-08-06 14:02:30.928 5225-5225/com.app.app D/DATASOURCE: NETWORK
2022-08-06 14:02:30.929 5225-5225/com.app.app I/System.out: /data/user/0/com.billbandits.hero/cache/image_cache/746b90d410c17e9d5a5d705a69e69d45afe12b20b8f234972e7394a6052e8033.1

那么我的问题现在是,如果有一个磁盘缓存键,为什么还需要从网络请求图像?
1个回答

2

您需要使用磁盘缓存而不是内存缓存。但默认情况下两者都已启用。

问题在于,默认情况下,coil根据Cache-Control http头字段来决定是否进行磁盘缓存。如果您需要忽略Cache-Control,则可以为ImageLoader设置respectCacheHeaders

        /**
         * Enables support for network cache headers. If enabled, this image loader will respect the
         * cache headers returned by network responses when deciding if an image can be stored or
         * served from the disk cache. If disabled, images will always be served from the disk cache
         * (if present) and will only be evicted to stay under the maximum size.
         *
         * Default: true
         */
        fun respectCacheHeaders(enable: Boolean) = apply {
            this.options = this.options.copy(respectCacheHeaders = enable)
        }

要检查此图像使用的数据源,您可以使用SubcomposeAsyncImage。例如:

SubcomposeAsyncImage(
    model = request,
    contentDescription = "Profile Picture",
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .clip(RoundedCornerShape(100.dp))
        .size(50.dp)
) {
    val state = painter.state
    if (state is AsyncImagePainter.State.Success) {
        SubcomposeAsyncImageContent()
        LaunchedEffect(Unit) { println(state.result.dataSource) }
    }
}

嗨@FishHawk!谢谢你,我已经更新了我的问题,包括设置imageLoader和在显示AsyncImage之前对每个请求进行排队,但是我仍然遇到问题,似乎图片加载需要很长时间,你能否再看一下并告诉我你的想法? - Meers E. Chahine
我们需要先检查图像是否被缓存。你可以使用 LaunchedEffect(painter.state) { println((painter.state as? AsyncImagePainter.State.Success)?.result?.dataSource) } 来检查它。 - FishHawk
我已经更新了我的回答。我只知道Glide有key,但我不知道Coil是否有。 - FishHawk
我在任何地方都没有使用“painter”,那么我应该从哪里假定这个值呢? - Meers E. Chahine
抱歉,我忘记了coil2.0的AsyncImage不再使用painter作为参数。我已经更新了我的答案。 - FishHawk
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接