Jetpack Compose:LazyColumn 不更新项目

Eyn*_*err 1 android android-jetpack-compose

我有一个lazyColumn从viewModel接收列表来创建项目:

@Composable
fun HomeList(
    modifier: Modifier = Modifier,
    dataList: List<Data>,
    listState: LazyListState = rememberLazyListState(),
    onClickItem: (Data) -> Unit,
    onLongPressItem: (Data) -> Unit
) {
    LazyColumn(
        modifier = modifier,
        state = listState
    ) {
        items(dataList) { data ->
            Log.d(TAG, "HomeList: add data $data")
            HomeListItem(
                data = data,
                onClick = onClickItem,
                onLongPressed = onLongPressItem
            )
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

该列表包装在 viewModel 中的 stateFlow 中,并在 Composable 中收集为状态:

    // viewModel
    ...
    private val _uiState = MutableStateFlow(
        HomeUiState(
            ...
            homeList = listOf()
        )
    )
    val uiState = _uiState as StateFlow<HomeUiState>
    ...
Run Code Online (Sandbox Code Playgroud)
// HomeScreen
val uiState by viewModel.uiState.collectAsState()
...
HomeList(
    modifier = Modifier
        .padding(it)
        .navigationBarsPadding(),
    dataList = uiState.homeList,
    listState = listState,
    onClickItem = { data ->
        ...
    },
    onLongPressItem = {
        ...
    }
)
Run Code Online (Sandbox Code Playgroud)

ViewModel将从Ro​​om数据库加载数据,并根据当前屏幕类型过滤掉不感兴趣的数据:

data class HomeUiState(
    val homeType: HomeType,
    val homeList: List<Data>
)

enum class HomeType {
    CREATED,
    VIEWED,
    STARRED,
    ARCHIVED
}
...
viewModelScope.launch(Dispatchers.IO) {
            repository.getAllDataFlow().collect { newList ->
                Log.d(TAG, "collect new list: $newList")
                when (_uiState.value.homeType) {
                    HomeType.CREATED -> _uiState.update { it.copy(homeList = homeList.filter { data -> data.status == MarkdownData.STATUS_INTERNAL }) }
                    HomeType.VIEWED -> _uiState.update { it.copy(homeList = homeList.filter { data -> data.status == MarkdownData.STATUS_EXTERNAL }) }
                    HomeType.STARRED -> _uiState.update { it.copy(homeList = homeList.filter { data -> data.isStarred == MarkdownData.IS_STARRED }) }
                    HomeType.ARCHIVED -> _uiState.update { it.copy(homeList = homeList.filter { data -> data.status == MarkdownData.STATUS_ARCHIVED }) }
                }
            }
        }
Run Code Online (Sandbox Code Playgroud)

这是我的问题:每次我删除 Room 数据库中的 Data 对象时,流程都会发出新值(删除后的数据列表),该值被收集并用于更新 Ui State 以进行重组。日志和实验表明确实如此:viewModel 收集新列表,然后lazyColumn 观察新列表并使用items语法创建可组合项,删除的项会从 UI 中明显删除。

然而,尽管使用新的数据列表进行重组,每个可组合项的数据对象仍然是旧的,并且不会按预期更新。例如,如果我有 a、b、c、d 的列表。删除a后,列表应该是b、c、d。UI中显示的列表确实代表了b、c、d,但它们的实际值对应的是旧的a、b、c,这阻碍了进一步的操作。但是,如果我刷新屏幕(重新启动应用程序或导航到其他屏幕然后弹出),一切都会恢复正常。

我想知道我是否错过了导致lazyColumn 项目更新UI 但不更新每个项目的实际数据的任何内容。谢谢!

pRa*_*NaY 7

我认为需要在LazyColumn项目中添加键,如下所示,这将有助于以独特的方式识别项目。

LazyColumn(
        modifier = modifier,
        state = listState
    ) {
        items(dataList,
            key = { listItem ->
                listItem.id // or any other unique
            })
        { data ->
            Log.d(TAG, "HomeList: add data $data")
            HomeListItem(
                data = data,
                onClick = onClickItem,
                onLongPressed = onLongPressItem
            )
        }
    }
Run Code Online (Sandbox Code Playgroud)