As the title says is there any way to know if an image is already in the cache?
I have a screen containing a list of image, clicking on an item will navigate to the detail screen for that item, the navigation is delayed until the item is successfully loaded.

I want when clicking on the loaded image, the navigation should happen immediately (the image is already in the cache). But I don't know how to check if the image is already in the cache.
Here are the codes:
@Composable
fun NavigateMap(navController: NavHostController = rememberNavController(),
viewModel: BookViewModel = viewModel(factory = BookViewModel.Factory)) {
val context= LocalContext.current
val imageLoader = ImageLoader.Builder(context)
.respectCacheHeaders(false)
.build()
val uiState by viewModel.uiState.collectAsState()
NavHost(navController = navController, startDestination = BookScreenMap.Start.name) {
composable(route = BookScreenMap.Start.name) {
BookHome(onBookClick = { id ->
viewModel.getPhotoById(id,imageLoader,context)
})
}
composable(route = BookScreenMap.Detail.name) {
DetailsScreen(
uiState.thumbnail, title = uiState.title,
authors = uiState.authors,
description = uiState.description)
}
}
val shouldNavigate=viewModel.shouldNavigate
LaunchedEffect(shouldNavigate) {
if(shouldNavigate){
navController.navigate(BookScreenMap.Detail.name)
viewModel.shouldNavigate = false
}
}
}
ViewMode Code:
class BookViewModel(private val bookRepository: BookRepository) : ViewModel() {
var shouldNavigate by mutableStateOf(false)
var fetchUiState:FetchUiState by mutableStateOf(FetchUiState.Loading)
private set
var fetchPhotoBook:FetchPhotoBook by mutableStateOf(FetchPhotoBook.Normal)
private set
private val _uiState = MutableStateFlow(BookUiState("", "","", "Chưa rõ",""))
val uiState = _uiState.asStateFlow()
init {
getListBook("live",10)
}
fun getPhotoById(id: String, imageLoader: ImageLoader,
context: Context) {
viewModelScope.launch {
val infoBook = safeApiCall {
bookRepository.getBookById(id).volumeInfo
}
infoBook?.let {
val imageUrl = it.imageLinks?.medium.toString().replace("http:", "https:")
updateBookUiState(
thumbnail =imageUrl,
title = it.title,
authors = it.authors?.joinToString(", ") ?: "Unknown",
description =HtmlCompat.fromHtml(it.description.orEmpty(), HtmlCompat.FROM_HTML_MODE_LEGACY).toString()
)
val cachedImage // how to check image in cache
if (cachedImage ) {
shouldNavigate=true
} else {
val request = ImageRequest.Builder(context)
.data(imageUrl)
.diskCachePolicy(CachePolicy.ENABLED)
.memoryCachePolicy(CachePolicy.ENABLED)
.networkCachePolicy(CachePolicy.ENABLED)
.diskCacheKey(imageUrl)
.memoryCacheKey(imageUrl)
.decoderFactory { _, _, _ ->
Decoder { DecodeResult(ColorDrawable(Color.BLACK), false) }
}
.listener(
onStart={ _ ->
fetchPhotoBook=FetchPhotoBook.Loading
Log.d("Request Start","Start")
}
,
onSuccess = { _, _ ->
shouldNavigate=true
}
)
.build()
imageLoader.enqueue(request)
}
} ?: run {
Log.d("BOOK_INFO", "No data found")
}
}
}
private suspend fun <T> safeApiCall(apiCall: suspend () -> T): T? {
return withContext(Dispatchers.IO) {
try {
apiCall()
} catch (e: HttpException) {
Log.e("ApiCall", "HTTP exception occurred", e)
null
} catch (e: IOException) {
Log.e("ApiCall", "Network or IO exception occurred", e)
null
} catch (e: Exception) {
Log.e("ApiCall", "Unexpected exception occurred", e)
null
}
}
}
...........
}
I would consider not to wait with the navigation until the image is loaded.
Instead, I would delegate the responsability for loading the thumbnail image to the DetailScreen. You can display a loading animation in Coil using a SubComposeAsyncImage:
SubcomposeAsyncImage(
model = "https://example.com/image.jpg",
loading = {
CircularProgressIndicator()
},
contentDescription = stringResource(R.string.description)
)
Also, as far as I can tell, your BookHome Composable already shows all thumbnails in a Grid. Are these coming from the same URL as the DetailScreen thumbnails? If yes, you can be sure that the images are already in cache.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With