Google Maps Compose聚类:实现选中标记差异化且不降低性能
性能优化方案及代码调整
针对你处理1000个聚类标记时遇到的性能问题,结合自定义选中样式的需求,可通过以下优化点避免UI冻结并保持样式修改能力:
1. 缓存Painter减少重复创建
painterResource虽有内部缓存,但在clusterItemContent高频重组场景下仍可能重复触发资源加载。将Painter提取到外部用remember缓存,避免每个标记都重新创建Painter实例。
2. 限制重组范围,减少不必要的UI更新
将标记渲染逻辑封装为独立Composable,并用key(item)确保仅当前标记或选中状态变化时才触发重组,避免全量标记重复渲染。
3. 用derivedStateOf缓存样式计算结果
颜色和尺寸的判断逻辑用derivedStateOf包裹,仅当选中状态或当前标记变化时才重新计算,避免每次重组都执行条件判断。
4. 替换位图为矢量图标(优先推荐)
WebP位图的缩放、渲染开销远大于矢量图(VectorDrawable),将marker图片转换为VectorDrawable格式,能大幅降低单标记的渲染耗时,对1000个标记的场景提升尤为明显。
5. 移除LaunchedEffect对Clustering的包裹
Clustering是UI组件,无需放在LaunchedEffect中执行,直接在正常UI层级渲染即可,避免协程调度带来的额外性能损耗。
修改后的完整代码示例
@Composable fun ClusterMarker( item: YourItemType, // 替换为你的实际Item类型 selectedItem: YourItemType?, painter: Painter ) { val color by remember(item, selectedItem) { derivedStateOf { if (selectedItem == item) { MaterialTheme.colorScheme.tertiary } else { MaterialTheme.colorScheme.secondary } } } val size by remember(item, selectedItem) { derivedStateOf { if (selectedItem == item) { Dimens.markerSelectedSize } else { Dimens.markerSize } } } Image( painter = painter, contentDescription = null, // 根据需求添加合适的描述 modifier = Modifier.size(size), colorFilter = ColorFilter.tint(color) ) } // 在原布局中调用Clustering Clustering( items = items, onClusterItemClick = { Timber.v("Marker clicked: ${it.name}") viewModel.selectItem(it) true }, clusterItemContent = { item -> val markerPainter = remember { painterResource(R.drawable.marker) } key(item) { ClusterMarker(item, selectedItem, markerPainter) } } )
额外优化提示
- 确保你的
YourItemType是稳定类型(比如用data class定义),这样selectedItem == item的比较才会高效,不会触发不必要的重组。 - 如果必须使用位图,可提前对图片进行预缩放处理,避免UI渲染时动态缩放带来的开销。
内容的提问来源于stack exchange,提问作者Psijic
相关产品推荐
相关产品推荐

