You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose点击按钮后LazyColumn数据不更新问题排查

问题

我使用Jetpack Compose开发页面,通过LazyColumn展示带表头的数据行,设置了两个按钮分别按姓名、就诊日期排序LazyColumn中的数据。目前UI显示正常,但点击排序按钮后,日志显示执行了排序逻辑,但VisitList未被调用,界面无任何变化。附上日志及代码,请求排查问题原因。

日志输出

Debug: Retrieving all patients
Debug: Retrieved 10 Patient objects
Debug: About to loop through 10 patients 
Debug: Calling VisitList with orderedList of size: 10
Debug: VisitList processing orderedList of size 10
Debug: About to loop through 10 patients 
Debug: Calling VisitList with orderedList of size: 10
Debug: VisitList processing orderedList of size 10
Debug: Sorting based on date
Debug: Sorting based on name

代码

class InsertionVisitHistoryScreen: Screen {
@Composable
override fun Content() {
    val navigator = LocalNavigator.currentOrThrow
    val patientRealm = openPatientRealm()
    val patients: RealmResults<Patient> = retrieveAllPatients(patientRealm)

    val visitList = remember { mutableStateListOf<VisitRowData>() } // creates a MutableList
    var orderedList by remember { mutableStateOf(visitList.toList()) }
    var firstTimeThrough = true

    MaterialTheme {
        Column(
            modifier = Modifier.fillMaxSize(),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text("Insertion Visit History")

            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(bottom = 20.dp),
                horizontalArrangement = Arrangement.SpaceEvenly
            ) {
                Button(onClick = {
                    closeGenericRealm(patientRealm)
                    navigator.pop()
                }) {
                    Text("Back")
                }
            }

            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(bottom = 20.dp),
                horizontalArrangement = Arrangement.SpaceEvenly
            ) {
                Button(onClick = {
                    Logger.d("Sorting based on name")
                    visitList.sortedWith(compareBy { it.getName() })
                    orderedList = visitList.toList()
                }, modifier = Modifier.padding(10.dp).padding(end = 180.dp)
                ) {
                    Text("Name")
                }

                Button(onClick = {
                    Logger.d("Sorting based on date")
                    visitList.sortedWith(compareBy { it.visitDate })
                    orderedList = visitList.toList()
                }, modifier = Modifier.padding(10.dp)
                ) {
                    Text("Visit Date")
                }
                Text("         Pellet Amount", textAlign = TextAlign.Center, modifier = Modifier.padding(top = 15.dp).wrapContentHeight(align = Alignment.CenterVertically))
                Text("           Lot number(s)" , textAlign = TextAlign.Center, modifier = Modifier.padding(top = 15.dp).wrapContentHeight(align = Alignment.CenterVertically))
            }

            Logger.d("About to loop through " + patients.size + " patients ")

            if(firstTimeThrough) {
                firstTimeThrough = false
                val visitRowDataArray = mutableListOf(VisitRowData())

                for (patient in patients) {
                    for (visit in patient.visits) {
                        val visitRowData = VisitRowData()
                        visitRowData.patientFirstName = patient.firstName
                        visitRowData.patientLastName = patient.lastName
                        visitRowData.patientLast4OfSSN = patient.lastFourOfSSN
                        visitRowData.visitDate = convertLongDateToString(visit.visitDate)

                        //Create an array of pellets
                        var pelletArray: Array<Pellet> = arrayOf(Pellet())
                        var lotArray: Array<String> = arrayOf("")

                        for (pellet in visit.pelletsUsed) {
                            pelletArray += pellet
                            lotArray += pellet.lotNumber
                        }

                        visitRowData.pelletsUsed = pelletArray
                        visitRowData.lotNumbers = lotArray

                        visitRowDataArray += visitRowData
                    }
                }

                visitRowDataArray.removeIf { it.getTotalPelletAmount() == 0}

                visitList.clear()

                visitList.addAll(visitRowDataArray)

                orderedList = visitList.toList()
            }

            Logger.d("Calling VisitList with orderedList of size: " + orderedList.size)
            VisitList(orderedList)
        }
    }
}


@Composable
fun VisitList(orderedList: List<VisitRowData>) {
    Logger.d("VisitList processing orderedList of size " + orderedList.size)

    LazyColumn {
        orderedList.forEachIndexed{index, visitItem ->
            item{
                Card(modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentHeight()
                    .padding(5.dp),
                    elevation = 10.dp) {
                        CreateARow(visitItem)
                    }
            }
        }
    }
}

@Composable
fun DropdownList(itemArray: Array<String>, selectedIndex: Int, modifier: Modifier, onItemClick: (Int) -> Unit) {

    var showDropdown by rememberSaveable { mutableStateOf(true) }
    val scrollState = rememberScrollState()

    Column(
        modifier = Modifier,
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {

        // button
        Box(
            modifier = modifier //                    .background(Color.Gray)
                .clickable { showDropdown = true },
            contentAlignment = Alignment.Center
        ) {
            Text(text = itemArray[selectedIndex], modifier = Modifier.padding(3.dp))
        }

        // dropdown list
        Box {
            if (showDropdown) {
                Popup(
                    alignment = Alignment.TopCenter,
                    properties = PopupProperties(
                        // CAN'T FIND THIS PARAM -> excludeFromSystemGesture = true,
                    ),
                    // to dismiss on click outside
                    onDismissRequest = { showDropdown = false }
                ) {

                    Column(
                        modifier = modifier
                            .heightIn(max = 90.dp)
                            .verticalScroll(state = scrollState)
                            .border(width = 1.dp, color = Color.Gray),
                        horizontalAlignment = Alignment.CenterHorizontally,
                    ) {

                        itemArray.onEachIndexed { index, item ->
                            if (index != 0) {
                                Divider(thickness = 1.dp, color = Color.LightGray)
                            }
                            Box(
                                modifier = Modifier
                                    .background(Color.Gray)
                                    .fillMaxWidth()
                                    .clickable {
                                        onItemClick(index)
                                        showDropdown = !showDropdown
                                    },
                                contentAlignment = Alignment.Center
                            ) {
                                Text(text = item)
                            }
                        }

                    }
                }
            }
        }
    }
}


@Composable
fun CreateARow(visit: VisitRowData) {
    var selectedIndex by rememberSaveable { mutableStateOf(0) }
    val buttonModifier = Modifier.width(120.dp)

    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(bottom = 3.dp),
        horizontalArrangement = Arrangement.SpaceBetween,
        verticalAlignment = Alignment.CenterVertically

    ) {
        Text(
            text = visit.getName(),
            textAlign = TextAlign.Start,
            modifier = Modifier
                .padding(3.dp) //                                .background(Color.LightGray)
            ,
        )

        Text(
            text = visit.visitDate,
            textAlign = TextAlign.Start,
            modifier = Modifier
                .padding(3.dp) //                                .background(Color.LightGray)
            ,
        )

        Text(
            text = visit.getTotalPelletAmount().toString(),
            textAlign = TextAlign.Center,
            modifier = Modifier
                .padding(3.dp) //                                .background(Color.LightGray)
            ,
        )

        DropdownList(
            itemArray = visit.getPelletToLotNumberArray(),
            selectedIndex = selectedIndex,
            modifier = buttonModifier,
            onItemClick = { selectedIndex = it })
    }
}

问题原因与修复方案

核心问题

  1. 排序方法未生效:sortedWith方法不会修改原列表,而是返回一个新的排序后列表。当前代码只调用了visitList.sortedWith(...)但未接收返回值,后续赋值给orderedList的还是原visitList的内容,等于没排序。
  2. 状态更新逻辑错误:orderedList是驱动UI更新的状态变量,排序后应该直接将排序后的新列表赋值给它,而非基于原始数据源重新转换。

修复步骤

修改排序按钮的点击逻辑,直接对orderedList进行排序并赋值回状态变量:

Button(onClick = {
    Logger.d("Sorting based on name")
    orderedList = orderedList.sortedWith(compareBy { it.getName() })
}, modifier = Modifier.padding(10.dp).padding(end = 180.dp)
) {
    Text("Name")
}

Button(onClick = {
    Logger.d("Sorting based on date")
    orderedList = orderedList.sortedWith(compareBy { it.visitDate })
}, modifier = Modifier.padding(10.dp)
) {
    Text("Visit Date")
}

额外优化建议

  • firstTimeThrough变量未用remember包裹,Compose重组时会被重置为true,导致重复初始化数据,应修改为:
    var firstTimeThrough by remember { mutableStateOf(true) }
    
  • 初始化时可直接将处理后的visitRowDataArray赋值给orderedList,减少不必要的中间操作:
    // 替换原visitList.clear()、addAll及orderedList赋值逻辑
    orderedList = visitRowDataArray.toList()
    visitList.addAll(visitRowDataArray) // 若后续无使用visitList的需求,可直接移除该变量
    

内容的提问来源于stack exchange,提问作者user443654

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 06:34:54