如何在Android Coil中获取一个未被缓存的新图像?

7

我使用 Jetpack Compose 和 Coil ImageLoader 库正在开发一个安卓应用。

它展示了用户的个人资料图片。

我从 API 中获取个人资料数据。 GET: /users/{userId}

响应中包含 userIdprofileImgKey

后端提供 GET: /photo/{userId} API 以获取用户资料图片。

问题是,如果某个用户更新了他/她的资料图片,其他用户仍然看到旧的图片而不是新的图片。

这是由于 Coil 对其进行了缓存。

如果关闭缓存选项,则可能可以解决此问题。但是我不想这样做。我不想失去性能优势。

当用户更新其个人资料图片时,profileImgKey 会更改。因此,我想将其作为缓存键。

但我不知道如何使用它。

4个回答

11
在 Coil 2.0.0 中,网络缓存的使用得到了极大的简化。
在 `rememberAsyncImagePainter` 中指定 `diskCacheKey` 和 `memoryCacheKey`,同时仍需要使用 `key` 触发重新组合。请保留 HTML 标签。
val context = LocalContext.current
key(key) {
    Image(
        rememberAsyncImagePainter(
            remember(url) {
                ImageRequest.Builder(context)
                    .data(url)
                    .diskCacheKey(url)
                    .memoryCacheKey(url)
                    .build()
            }
        ),
        null
    )
}

使用图像加载器清除缓存:

val imageLoader = context.imageLoader
imageLoader.diskCache?.remove(url)
imageLoader.memoryCache?.remove(MemoryCache.Key(url))

Coil 1.4.0 的答案

Coil 有两个级别的缓存:

  1. For network calls Coil uses OkHttp, to access its cache you need to create it manually as shown in documentation. I think in this case it's best to store both the cache and the image loader in the DI, but you can also create a composition local to access this cache from any composable:

    val LocalCoilHttpCache = staticCompositionLocalOf<Cache> {
        error("coilHttpCache not provided")
    }
    

    Provide it in your activity/fragment:

    val cache = CoilUtils.createDefaultCache(this)
    val imageLoader = ImageLoader.Builder(this)
        .okHttpClient {
            OkHttpClient.Builder()
                .cache(cache)
                .build()
        }
        .build()
    
    setContent {
        CompositionLocalProvider(
            LocalImageLoader provides imageLoader,
            LocalCoilHttpCache provides cache,
        ) {
            // your application
        }
    }
    

    Get it in any composable

    val httpCache = LocalCoilHttpCache.current
    

    Then, regardless of where you store it in the DI or in the composition local, you can clear the necessary cache with the following code:

    val urlIterator = httpCache.urls()
    while (urlIterator.hasNext()) {
        if (urlIterator.next() == urlToRemove) {
            urlIterator.remove()
        }
    }
    
  2. After downloading an image from the network, it is converted to Bitmap. These bitmaps are cached with Memory cache, so you need to clear that as well. The easiest way, according to the documentation, is to specify a cache key, e.g. URL:

    rememberImagePainter(
        url,
        builder = {
            memoryCacheKey(MemoryCache.Key(url))
        }
    ),
    

    Then you can clean it up:

    val loader = LocalImageLoader.current
    // or out of composable
    val loader = Coil.imageLoader(context)
    // ..
    loader.memoryCache.remove(MemoryCache.Key(url))
    
最后一步是强制重新组合图片。您可以使用key来执行此操作,指定要更改的值,在您的情况下,profileImgKey应该有效:
key(profileImgKey) {
    Image(
        rememberImagePainter(
            // ...

很棒的答案 - 有效。在看到这里关键的重要最后一步使用key(..)触发重新组合之前,我已经在我的代码中完成了所有工作。 - zaifrun
我正在使用Uri,它期望我提供一个字符串。我如何知道应该是什么样的字符串? - user924

2

确保您获取到最新的图片,即使它发生了变化,最简单的方法是在url末尾添加一个查询参数,其值为随机数。例如:

someurl/user1.jpg?49610269

并且可以这样完成:

val imageUrl = "someUrl/user1.jpg?" + (0..1_000_000).random()

如果您的URL已经有查询参数,请添加一个新的参数,这个URL没有使用过。
缓存中的图像仅在URL(包括查询字符串)未更改时被重用。通过更改URL,您可以强制Coil获取最新的图像。

每次加载图片时,这只会添加新的缓存。对于上述情况来说,这是没有用的。 - undefined

0

为了加载一个在 Coil 中没有缓存的新图片,请在该特定的 ImageView 上尝试以下代码:

imgVw.load(imgUrl) {
    memoryCachePolicy(CachePolicy.DISABLED)
}

你没有仔细阅读问题。 - undefined

0
最简单的解决方案是更新URL:
val builder: Uri.Builder = url.buildUpon()
builder.appendQueryParameter("imageCacheKey", UUID.randomUUID().toString())
val newUri = builder.build()

每次加载图像时,这只会添加新的缓存。对于上述情况来说,这并没有什么用处。 - undefined

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