I'm using `LazyVerticalGrid` to loading images. If...
# compose
r
I'm using
LazyVerticalGrid
to loading images. If there's any error while decoding image bitmap, it shouldn't be loaded (as per code in thread), but
LazyVerticalGrid
is using empty cell (shown in image) instead of avoiding that item. what should i do to resolve it?
Copy code
@Composable
fun ImageGridView(
    context: Context,
    images: List<ImageMetaData>
) {
    LazyVerticalGrid(cells = GridCells.Fixed(3)) {
        items(images) { image ->
            var bitmap: Bitmap? = null
            try {
                bitmap = context.contentResolver.loadThumbnail(image.uri, Size(640, 480), null)
            } catch (e: IOException) {
                Log.d(TAG, "IO exception: ${e.message}")
            }

            bitmap?.let {
                Image(
                    modifier = Modifier
                        .fillMaxWidth()
                        .aspectRatio(1f)
                        .border(1.dp, Color.White),
                    bitmap = it.asImageBitmap(),
                    contentDescription = null,
                    contentScale = ContentScale.Crop
                )
            }
        }
    }
}
a
that's an interesting case. assuming it's a permanent error that retrying would not fix, I would suggest adding a hoisted state associated with the list with a method like
reportLoadError(imageIdentifierKey: String)
that you would call in the catch block. then your higher-level code should mutate the list to remove that image, causing your whole
ImageGridView
to recompose
a
this code should also try to avoid loading images from the contentResolver directly in composition like this too
r
@Alexandre Elias [G] but that can cause major ui issue if I've somewhere down to 2000th item and it recompose. Correct?
@Adam Powell could you please suggest another option? I tried using try catch block in
LaunchedEffect
but it says inappropriate method blocking call for
loadThumbnail()
and do nothing.
a
I think it should be possible to make what I suggested work without major UI jank, for example the
LazyListState
scroll position will not be affected as long as the item with an error is not above the top of the screen (and even then a manual adjustment to the state should be possible)
a
You'll want to swap to another dispatcher using withContext or something but doing IO in composition is just as inappropriate of a blocking call, it just doesn't have a warning in the ide about it
r
I tried following, but its not working, nothing is showing
Copy code
@ExperimentalFoundationApi
@Composable
fun ImageGridView(
    modifier: Modifier = Modifier,
    context: Context,
    images: List<ImageMetaData>,
    onClick: (ImageMetaData) -> Unit
) {
    val scope = rememberCoroutineScope()

    LazyVerticalGrid(
        modifier = modifier,
        cells = GridCells.Fixed(4)
    ) {
        items(images) { image ->
            var bitmap: Bitmap? = null
            scope.launch {
                withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
                    try {
                        bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                            context.contentResolver.loadThumbnail(image.uri, Size(640, 480), null)
                        } else {
                            MediaStore.Images.Thumbnails.getThumbnail(
                                context.contentResolver,
                                image.id,
                                MediaStore.Images.Thumbnails.MINI_KIND,
                                null
                            )
                        }
                    } catch (e: IOException) {
                    }
                }
            }

            bitmap?.let {
                Image(
                    modifier = Modifier
                        .fillMaxWidth()
                        .aspectRatio(1f)
                        .border(1.dp, Color.White)
                        .clickable { onClick(image) },
                    bitmap = it.asImageBitmap(),
                    contentDescription = null,
                    contentScale = ContentScale.Crop
                )
            }
        }
    }
}
102 Views