Issue
I am developing an android app using the Jetpack Compose with Coil ImageLoader library.
It shows a user's profile image.
I receive the profile data from the API. GET: /users/{userId}
The response contains userId
and profileImgKey
.
For the user profile image, Backend provides GET: /photo/{userId}
API.
But the problem is that if some user update his/her profile image, other users still see the previous profile image not the new image.
Because it is cached by Coil.
If I turn-off the caching option, it may work fine. But I don't want to do it. I don't want to lose the performance benefit.
When the user update their profile image, the profileImgKey
is changed.
So I want to use this as a cache key.
But I don't know how to use this.
Solution
In Coil 2.0.0 working with network cache is significantly simplified.
Specify diskCacheKey
and memoryCacheKey
in rememberAsyncImagePainter
, also key
is still needed to trigger recomposition.
val context = LocalContext.current
key(key) {
Image(
rememberAsyncImagePainter(
remember(url) {
ImageRequest.Builder(context)
.data(url)
.diskCacheKey(url)
.memoryCacheKey(url)
.build()
}
),
null
)
}
And clear cache using image loader:
val imageLoader = context.imageLoader
imageLoader.diskCache?.remove(url)
imageLoader.memoryCache?.remove(MemoryCache.Key(url))
Answer for Coil 1.4.0
Coil has a cache on two levels:
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() } }
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))
The last step is to force image recomposition. You can do this with key
, specifying the value to change, in your case profileImgKey
should work:
key(profileImgKey) {
Image(
rememberImagePainter(
// ...
Answered By - Pylyp Dukhov
Answer Checked By - Candace Johnson (JavaFixing Volunteer)