Compose 列表页值班排查表:出现卡片错位时先查筛选状态、稳定 key 还是滚动锚点
## Compose 列表页问题
今天这篇也不按通用教程写,而是按一张值班排查表来写。因为 Compose 列表页 一旦在真实业务里出现卡片错位、筛选后内容串线、返回页面状态残留,团队最缺的从来不是更多概念,而是一个能在十几分钟内快速判断问题落在哪一层的顺序。
真正容易把人带偏的地方,是把所有视觉异常都叫成‘重组问题’。但放到工程现场,更多时候错的是状态源、稳定 key、滚动锚点三者没有一起收口。只要这三样有一个沿用了旧数据,界面再顺也会在筛选、刷新、返回时露馅。
## 方案先给到
最短路径不是继续改动画,而是把排查压成三问:列表数据是谁产出的、key 是否真的稳定、滚动位置是否和当前过滤条件一起保存。只要这三问里有一问答不清,后面的 UI 修补基本都只是延迟问题暴露。
Compose 列表页 真正需要的不是“更多技巧”,而是“一个先后顺序对的排查表”。顺序一对,问题通常会比想象中更快现形。
## Compose 列表页关键实现
1. 状态对象
data class FeedState(
val filter: String,
val ids: List,
val anchorIndex: Int
)
2. 排查命令
adb shell am profile start com.example.app /sdcard/compose.trace
adb pull /sdcard/compose.trace ./compose.trace
adb logcat -d | findstr /I "compose lazycolumn key state"
3. 稳定 key 校验
fun keysAreStable(ids: List): Boolean {
return ids.distinct().size == ids.size
}
## Compose 列表页注意点
第一类高频误判,是看到闪动就去继续调动画,其实真正的问题是旧对象被错误复用。第二类误判,是筛选条件改了,但状态对象没换,导致卡片继续绑定旧内容。第三类误判,是滚动恢复只跟页面生命周期绑定,没有跟当前数据集一起变化。
所以排查 Compose 列表页 时,先查状态关系,再谈 UI 细节。只看视觉表现,很容易把根因看歪。
## Compose 列表页报错与排查
1. 筛选后内容错位
如果切一次筛选以后就出现卡片内容对不上、顺序异常或者旧状态残留,先查 LazyColumn 的 key,再查筛选后列表是不是重新生成了对象集合。只要对象集合还是旧的,后面越修越乱。
adb logcat -d | findstr /I "compose recomposition lazycolumn key"
adb shell am profile start com.example.app /sdcard/compose.trace
2. 返回页面后滚动位置不对
如果返回列表以后滚动位置漂了,优先检查 anchor 是否和 filter 一起保存,再看页面重建时有没有把旧列表锚点直接套到新列表。滚动恢复如果不跟数据条件走,问题只会反复。
data class ScrollAnchor(
val filter: String,
val index: Int,
val offset: Int
)
## Compose 列表页可运行片段
1. 最小状态对象
data class ComposeCheckState(
val filter: String,
val ready: Boolean,
val updatedAt: Long
)
2. 本地执行入口
fun runComposeDutyCheck() {
println(ComposeCheckState("all", true, System.currentTimeMillis()))
}
3. 最小验证命令
adb shell am profile start com.example.app /sdcard/compose.trace
adb pull /sdcard/compose.trace ./compose.trace
adb logcat -d | findstr /I "compose filter key anchor state"
