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.
CodePudding user response:
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(
// ...
CodePudding user response:
The easiest way to ensure that you get a fresh image, even when it changes is to append a query parameter to the url with a random value. For example:
someurl/user1.jpg?49610269
And done like this:
val imageUrl = "someUrl/user1.jpg?" (0..1_000_000).random()
If your url already has query parameters, just add a new parameter that your url doesn't use.
Images in caches are reused whenever the url (including the query string) does not change. By changing the url, you force Coil to obtain the most recent image.