LazyColumn 与来自位图源的图像闪烁/闪烁

LazyColumn with Image from bitmap source blinking / flashing

我是 Jetpack Compose 的新手。我目前正在开发一个聊天应用程序。我要求用户从图库中选择一张图片或用相机拍照。然后我将文件 Uri 保存到数据库中,然后收听所有消息的列表。更新此列表时,此图像正在重新组合并闪烁。

视图模型中的消息列表:

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)
            }
    }
}

主聊天屏幕:

...
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
                )
                ...
            }
        }
    }

我的 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())
}

我尝试了几种方法,但图像总是闪烁。

LazyColumn 使用 key 参数重用项目的视图,默认情况下它等于项目索引。您可以提供正确的 key(类似于消息 id)以便正确重用视图:

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
            )
                ...
        }
    }
}