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 }) } }
问题原因与修复方案
核心问题
- 排序方法未生效:
sortedWith方法不会修改原列表,而是返回一个新的排序后列表。当前代码只调用了visitList.sortedWith(...)但未接收返回值,后续赋值给orderedList的还是原visitList的内容,等于没排序。 - 状态更新逻辑错误:
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
相关产品推荐
相关产品推荐

