1

I am trying to load a list of object in a column using jetpack compose.

The problem is the image is making screen lag.

Here's my code - single list item composable function.

fun SoulProfilePreviewSingleItem(
    soul: Souls,
    soulWinningViewModel: SoulWinningViewModel,
    onClick: () -> Unit
) {
    val lazyListState = rememberLazyListState()
    /* val localImage = if (soul.localImage.isNotBlank())
         rememberImagePainter(getBase64StringToImage(soul.localImage)) else null*/
    LaunchedEffect(key1 = soulWinningViewModel.nurtureVsFollowUpTabIndex.value) {
        lazyListState.animateScrollToItem(0)
//        if (soul.localImage.isNotBlank()){

//        }
    }
    val isManaging = soulWinningViewModel.isManagingList.value
    var isDeleted by remember {
        mutableStateOf(false)
    }

    val setVisibility: (Boolean) -> Unit = {
        isDeleted = it
    }


    AnimatedVisibility(
        visible = isDeleted.not() &&
                if (soulWinningViewModel.userIsSearchingFor.value.isNotEmpty() && isManaging.not())
                    soul.name.contains(soulWinningViewModel.userIsSearchingFor.value, true) ||
                            soul.followUpActions.toString()
                                .contains(soulWinningViewModel.userIsSearchingFor.value, true) else
                    true
    ) {

        with(soul) {
            Column {
                Box(
                    modifier = Modifier
                        .height(60.dp)
                        .background(MaterialTheme.colorScheme.background)
                        .fillMaxWidth(),
                    contentAlignment = Alignment.BottomEnd
                ) {
                    Row(
                        Modifier
                            .fillMaxSize(),//.clickable { onClick() },
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        Row(
                            verticalAlignment = Alignment.Top,
                            modifier = Modifier
                                .padding(start = brc_DP_small)
                                .padding(bottom = 6.dp, top = 6.dp)
                        ) {
                            /*if (soul.localImage.isNotBlank()) {
                                GlideImage(
                                    model = ,
                                    // Crop, Fit, Inside, FillHeight, FillWidth, None
                                    contentScale = ContentScale.Crop,
                                    // shows an image with a circular revealed animation.


                                )
                                Log.e("BITMAP","onResourceReady test")
                                val image = loadPicture(url = soul.localImage, defaultImage = R.drawable.ic_brc_logo).value
                                image?.let { img->
                                    Image(
                                        // Can crash this
                                        bitmap =img.asImageBitmap(),
                                        contentDescription = null,
                                        modifier = Modifier
                                            .clip(RoundedCornerShape(50))
                                            .size(30.dp),
                                        contentScale = ContentScale.Crop
                                    )
                                }
                            }*/

                            if (soul.localImage.isNotBlank()) {
//                                val imageLoader = rememberImagePainter(getBase64StringToImage(soul.localImage))
                                Image(
//                                    painter = imageLoader
                                    // Can crash this
                                    bitmap = (
                                            getBase64StringToImage(soul.localImage).asImageBitmap()
                                            ),
                                    contentDescription = null,
                                    modifier = Modifier
                                        .clip(RoundedCornerShape(50))
                                        .size(30.dp),
                                    contentScale = ContentScale.Crop
                                )
                            } else {
                                Image(
                                    // Can crash this
                                    painterResource(id = R.drawable.ic_brc_logo),
                                    contentDescription = null,
                                    modifier = Modifier
                                        .clip(RoundedCornerShape(50))
                                        .size(30.dp),
                                    contentScale = ContentScale.Crop
                                )
                            }
                        }

                        Column(
                            modifier = Modifier
                                .padding(top = brc_DP_small)
                                .weight(1f)
                                .fillMaxWidth()
                                .fillMaxHeight()
                                .padding(start = brc_DP_smaller),
                            verticalArrangement = Arrangement.SpaceBetween
                        ) {
                            Column(
                                modifier = Modifier
                                    .weight(1f)
                                    .fillMaxSize()
                            ) {
                                // This is the place where signle soul is getting showed......
                                Text(
                                    text = name,
                                    style = if (isManaging.not()) MaterialTheme.typography.labelSmall.copy(
                                        fontWeight = FontWeight(500),
                                        letterSpacing = 0.7.sp
                                    )
                                    else MaterialTheme.typography.labelSmall
                                        .copy(
                                            fontSize = 10.sp
                                        ),
                                    modifier = Modifier,
                                    maxLines = 1,
                                )

                                if (isManaging.not()) {
                                    Text(
                                        text = SimpleDateFormat(
                                            "dd-MMM-yyyy",
                                            Locale.UK
                                        ).format(
                                            createdOn
                                        ),
                                        style = MaterialTheme.typography.bodySmall.copy(fontSize = 9.sp),
                                        color = Color.Gray,
                                        modifier = Modifier
                                    )
                                }

                            }

                            if (isBrcMember) {
                                Text(
                                    text = "BRC Member",
                                    style = MaterialTheme.typography.labelSmall.copy(
                                        fontSize = 7.sp,
                                        fontStyle = FontStyle.Italic
                                    ),
                                    color = brc_blue_color,
                                    modifier = Modifier.padding(bottom = brc_DP_smallest)
                                )
                            }
                        }
                    }

                    var externClick by remember {
                        mutableStateOf(false)
                    }

                    Column(modifier = Modifier.padding(brc_DP_small)) {
                        AddSoulFollowUpActionButton(
                            soul = soul,
                            soulWinningViewModel = soulWinningViewModel,
                            visible = soulWinningViewModel.nurtureVsFollowUpTabIndex.value == 1,
                            externClick = externClick,
                            onFinished = { externClick = false }
                        ) {
                            setVisibility(it)
                        }
                    }

                    //TODO:Check Click area ...
                    Row(modifier = Modifier.fillMaxSize()) {
                        Spacer(
                            modifier = Modifier
                                .fillMaxSize()
                                .weight(1.4f)
                                .clickable(
                                    interactionSource = MutableInteractionSource(),
                                    indication = null
                                ) { onClick() })
                        if (soulWinningViewModel.nurtureVsFollowUpTabIndex.value == 1 || isManaging) {
                            Spacer(
                                modifier = Modifier
                                    .fillMaxSize()
                                    .weight(0.6f)
                                    .clickable(
                                        interactionSource = MutableInteractionSource(),
                                        indication = null
                                    ) { externClick = !externClick })
                        }
                    }
                }

                Spacer(
                    modifier = Modifier
                        .padding(start = 28.dp)
                        .fillMaxWidth() //.then(if (isManaging.not()) Modifier.width(150.dp) else Modifier.fillMaxWidth())
                        .height(0.3.dp)
                        .background(Color.LightGray)
                )
            }
        }
    }
}

caller of list composable function.

forEach {
                            SoulProfilePreviewSingleItem(
                                soul = it,
                                soulWinningViewModel
                            ) {
                                soulWinningViewModel.currentSoul.value = it
                                navController.navigate(route = SoulWinningRoutes.PROFILE)
                            }
                        }

Whenever I am trying to show Image() of my soul object I am getting glitches and my screens takes more time to load itself.

I am storing image as string in local room database and trying to retrieve it back converting it to bitmapImage.

Code for conversation.

fun getBase64StringToImage(base64String: String): Bitmap {
    val decodedString: ByteArray = Base64.decode(base64String, Base64.DEFAULT)
    val decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.size)
    return decodedByte
    // this is taking a lot of time and making my Ui performance dull.
}

Is there any way I can achieve this functionality with good performance. Like loading Image in separate scope or anything else.

I have already tried using rememberImagePainter and Glide Coil. rememberImagePainter making my performance worst.

Please feel free to give me suggestions, I am still in learning stage.

Thanks in advance.

5
  • I think you should use coil async image Commented Dec 23, 2022 at 21:55
  • Search Philip lancker jetpack compose on YouTube ... Commented Dec 23, 2022 at 21:56
  • I think you should use coroutine scope it opens a new thread that runs concurrently to the UI thread that will load the images Commented Dec 23, 2022 at 21:57
  • 1
    I have tried using both and I am unable to get desired results because We cannot open a corotuine scope at the time of assigning Image( imagePainter ="") coroutine is a job and I want converted value back at the desired time. Commented Dec 28, 2022 at 5:51
  • 1
    I learned most of jetpack compose from philip lancker but I don't find any video related to this problem. Commented Dec 28, 2022 at 5:52

1 Answer 1

0

Im currently doing a background loading for this and I got a lot of lagging effect on my list:

@Composable
fun PictureWithBlurHash(
    modifier: Modifier = Modifier,
    colorFilter: ColorFilter? = null,
    contentScale: ContentScale = ContentScale.Fit,
    description: String = "",
    filterQuality: FilterQuality = FilterQuality.High,
    blurHash: String
) {
    val bitmap = remember {
        mutableStateOf<Bitmap?>(null)
    }

    if (bitmap.value == null) {
        Box(
            contentAlignment = Alignment.Center,
            modifier = modifier
        ) {
            Z17Shimmer(modifier = Modifier.fillMaxSize())
        }
    } else {
        bitmap.value?.let {
            it.prepareToDraw()
            Image(
                bitmap = it.asImageBitmap(),
                contentDescription = description,
                colorFilter = colorFilter,
                modifier = modifier,
                contentScale = contentScale,
                filterQuality = filterQuality
            )
        }
    }

    LaunchedEffect(Unit) {
        delay(500)
        bitmap.value = BlurHashDecoder.decode(blurHash, 140, 140, 1f, false)
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.