I'm new to Jetpack Compose. I am currently developing a chat application. I ask the user to choose an image from the gallery or take a picture from the camera. Then I save the file Uri to the database and then listen to the list of all messages. When this list is updated, this image is recomposing and it flashes.
Messages list in viewmodel:
private var _messages = MutableStateFlow<List<ChatUiMessage>>(mutableListOf())
val messages: StateFlow<List<ChatUiMessage>> = _messages
...
private fun observeMessages() {
viewModelScope.launch {
chatManager.observeMessagesFlow()
.flowOn(dispatcherIO)
.collect {
_messages.emit(it)
}
}
}
Main chat screen:
...
val messages by viewModel.messages.collectAsState(listOf())
...
val listState = rememberLazyListState()
LazyColumn(
modifier = modifier.fillMaxWidth(),
reverseLayout = true,
state = listState
) {
itemsIndexed(items = messages) { index, message ->
when (message) {
...
is ChatUiMessage.Image -> SentImageBlock(
message = message
)
...
}
}
}
My SentImageBlock:
@Composable
private fun SentImageBlock(message: ChatUiMessage.Image) {
val context = LocalContext.current
val bitmap: MutableState<Bitmap?> = rememberSaveable { mutableStateOf(null) }
bitmap.value ?: run {
LaunchedEffect(Unit) {
launch(Dispatchers.IO) {
bitmap.value = try {
when {
Build.VERSION.SDK_INT >= 28 -> {
val source = ImageDecoder.createSource(context.contentResolver, message.fileUriPath.toUri())
ImageDecoder.decodeBitmap(source)
}
else -> {
MediaStore.Images.Media.getBitmap(context.contentResolver, message.fileUriPath.toUri())
}
}
} catch (e: Exception) {
null
}
}
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.padding(end = 16.dp, top = 16.dp, bottom = 16.dp)
.heightIn(max = 200.dp, min = 200.dp)
) {
bitmap.value?.let {
Image(
bitmap = it.asImageBitmap(),
contentDescription = null,
modifier = Modifier
.wrapContentSize()
.align(Alignment.CenterEnd)
)
}
}
StandardText(text = message.sendFileStatus.toString())
StandardText(text = message.fileType.toString())
}
I have tried several things and either is the Image always blinking.
Example:
CodePudding user response:
LazyColumn
reuses views for items using key
argument, and by default it's equal to item index. You can provide a correct key
(something like message id
) for views to be reused correctly:
val messages = listOf(1,2,3)
LazyColumn(
modifier = modifier.fillMaxWidth(),
reverseLayout = true,
state = listState
) {
itemsIndexed(
items = messages,
key = { index, message -> message.id }
) { index, message ->
when (message) {
...
is ChatUiMessage.Image -> SentImageBlock(
message = message
)
...
}
}
}