Improved avatar loading

Now avatar loading checks first if there is a cached avatar and before showing the placeholder, to avoid showing the placeholder for a moment when a cached version is available.

This will reduce CPU usage by a tiny bit since the placeholder won't have to be rendered.
This commit is contained in:
Abdelilah El Aissaoui 2022-08-06 03:46:09 +02:00
parent 20e23a9750
commit dc31181387

View File

@ -20,12 +20,18 @@ object NetworkImageLoader {
private val loadingImagesSemaphore = Semaphore(MAX_LOADING_IMAGES) private val loadingImagesSemaphore = Semaphore(MAX_LOADING_IMAGES)
private val cache: ImagesCache = InMemoryImagesCache private val cache: ImagesCache = InMemoryImagesCache
fun loadCachedImage(url: String): ImageBitmap? {
val cachedImage = cache.getCachedImage(url)
return cachedImage?.toComposeImage()
}
suspend fun loadImageNetwork(url: String): ImageBitmap? = withContext(Dispatchers.IO) { suspend fun loadImageNetwork(url: String): ImageBitmap? = withContext(Dispatchers.IO) {
try { try {
val cachedImage = cache.getCachedImage(url) val cachedImage = loadCachedImage(url)
if (cachedImage != null) if (cachedImage != null)
return@withContext cachedImage.toComposeImage() return@withContext cachedImage
loadingImagesSemaphore.acquireAndUse { loadingImagesSemaphore.acquireAndUse {
val imageByteArray = loadImage(url) val imageByteArray = loadImage(url)
@ -34,7 +40,7 @@ object NetworkImageLoader {
} }
} catch (ex: Exception) { } catch (ex: Exception) {
if(ex !is FileNotFoundException) if (ex !is FileNotFoundException)
ex.printStackTrace() ex.printStackTrace()
} }
@ -54,24 +60,40 @@ object NetworkImageLoader {
@Composable @Composable
fun rememberNetworkImageOrNull(url: String, placeHolderImageRes: String? = null): ImageBitmap? { fun rememberNetworkImageOrNull(url: String, placeHolderImageRes: String? = null): ImageBitmap? {
val networkImageLoader = NetworkImageLoader val networkImageLoader = NetworkImageLoader
val cacheImageUsed = remember { ValueHolder(false) }
var image by remember(url) { var image by remember(url) {
val placeHolderImage = if (placeHolderImageRes != null) val cachedImage = networkImageLoader.loadCachedImage(url)
useResource(placeHolderImageRes) {
val image: ImageBitmap? = when {
cachedImage != null -> {
cacheImageUsed.value = true
cachedImage
}
placeHolderImageRes != null -> useResource(placeHolderImageRes) {
Image.makeFromEncoded(it.toByteArray()).toComposeImageBitmap() Image.makeFromEncoded(it.toByteArray()).toComposeImageBitmap()
} }
else else -> null
null }
mutableStateOf(placeHolderImage) return@remember mutableStateOf(image)
} }
LaunchedEffect(url) { LaunchedEffect(url) {
val networkImage = networkImageLoader.loadImageNetwork(url) if(!cacheImageUsed.value) {
if (networkImage != null) val networkImage = networkImageLoader.loadImageNetwork(url)
image = networkImage
if (networkImage != null && !cacheImageUsed.value) {
image = networkImage
}
}
} }
return image return image
} }
fun ByteArray.toComposeImage() = Image.makeFromEncoded(this).toComposeImageBitmap() fun ByteArray.toComposeImage() = Image.makeFromEncoded(this).toComposeImageBitmap()
internal class ValueHolder<T>(var value: T)