LazyColumn内使用CustomView(含/不含AndroidView)如何实现并解决滑动卡顿问题?
优化方案
以下是不需要完全重写为Compose组件的可行优化方案,按优先级从高到低排列:
- 为LazyColumn的item指定唯一稳定key
默认情况下LazyColumn使用item位置作为key,当列表滑动、数据集变更时,Compose会错误判定item为新实例,触发AndroidView的factory反复执行重建View。给items绑定event的唯一标识作为key,即可让Compose正确复用item实例,避免不必要的View重建。 - 标记数据类为稳定类型
给EventOverviewUiModel添加@Immutable注解(要求类所有属性都是不可变的val类型),让Compose可以正确判断数据是否发生变更,只有当event真实变化时才会触发update回调更新View,减少不必要的重绘。 - 固定item高度避免重复测量
如果你的EventItem高度是固定的,直接给AndroidView的modifier指定明确高度,避免每次bind数据时都重新执行测量布局流程,大幅降低渲染开销。 - 优化回调与初始化逻辑
- 所有只需要执行一次的初始化操作(比如子布局inflate、固定点击监听设置)都放到
factory代码块中,不要放到update里重复执行 - 用
rememberUpdatedState包裹回调参数,避免每次重组生成新的回调实例触发不必要的item重组,也不需要在update中重复设置监听器
- 所有只需要执行一次的初始化操作(比如子布局inflate、固定点击监听设置)都放到
- 优化bind方法逻辑
确保bind方法内只有纯数据赋值的轻量操作,不要做耗时计算、文件读写、同步加载图片这类阻塞主线程的操作,图片加载等异步操作不要阻塞UI线程。
优化后示例代码
数据类标注
@Immutable data class EventOverviewUiModel( val id: String, // 唯一标识,作为item的key // 其他属性均为不可变val类型 )
列表实现
LazyColumn { // 绑定唯一key items(events, key = { it.id }) { event -> EventItem(event, callBack) } } @Composable private fun EventItem( event: EventOverviewUiModel, callBack : (EventsAdapterEvent) -> Unit ) { // 记住最新回调实例,避免触发不必要重组 val currentCallback by rememberUpdatedState(callBack) AndroidView( modifier = Modifier .fillMaxWidth() .height(80.dp), // 替换为你实际的item固定高度 factory = { context -> EventOverviewView(context).apply { // 所有初始化操作仅执行一次 setOnClickListener { currentCallback.invoke(EventsAdapterEvent.Click(event)) } } }, update = { view -> // 仅做轻量数据更新 view.bind(event) } ) }
如果以上优化后仍有卡顿,可以进一步对自定义View本身做优化,比如减少子View层级、去掉多余的背景绘制、启用硬件加速等,不需要重写为Compose组件即可达到接近原生RecyclerView的滑动流畅度。
内容的提问来源于stack exchange,提问作者robert lurese
相关产品推荐
相关产品推荐

