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

Compose中Google Map跨导航保留CameraPositionState避免崩溃方案咨询

Compose Google Map 跨导航保留CameraPositionState且避免崩溃的解决方案

错误原因解析

java.lang.IllegalStateException: CameraPositionState may only be associated with one GoogleMap at a time 本质是同一个CameraPositionState实例不能同时绑定到多个GoogleMap组件。当快速在Map和History页面切换时,前一个MapScreen的GoogleMap还未完成销毁(Compose重组/组件销毁存在延迟),新的MapScreen又绑定了同一个全局状态,触发了冲突。

以下是两种可靠的解决思路:


方案一:利用导航组件SavedStateHandle保存状态(推荐)

借助导航组件的SavedStateHandle持久化相机位置,既保留状态,又保证每次进入MapScreen时使用独立的CameraPositionState实例,避免绑定冲突。

代码实现:

@Composable
fun MapScreen(navController: NavHostController) {
    // 获取当前页面的BackStackEntry及SavedStateHandle
    val backStackEntry = navController.currentBackStackEntryAsState().value
    val savedStateHandle = backStackEntry?.savedStateHandle ?: remember { SavedStateHandle() }

    // 初始化默认相机位置,优先读取已保存的位置
    val defaultCameraPos = CameraPosition.fromLatLngZoom(LatLng(39.9042, 116.4074), 10f)
    val savedCameraPos = savedStateHandle.get<CameraPosition>("camera_position") ?: defaultCameraPos

    // 创建当前页面独立的CameraPositionState
    val cameraPositionState = rememberCameraPositionState(initialPosition = savedCameraPos)

    // 防抖监听相机位置变化,保存到SavedStateHandle
    LaunchedEffect(cameraPositionState) {
        snapshotFlow { cameraPositionState.position }
            .debounce(500) // 避免频繁触发保存
            .collect { position ->
                savedStateHandle["camera_position"] = position
            }
    }

    GoogleMap(
        cameraPositionState = cameraPositionState
    ) {
        // 地图标记、控件等内容
    }
}

方案二:用ViewModel管理状态(适合复杂场景)

通过ViewModel持有相机状态,同时在MapScreen销毁时清空状态引用,避免旧状态与新GoogleMap组件绑定冲突。

代码实现:

  1. 创建MapViewModel:
class MapViewModel : ViewModel() {
    private var _cameraPositionState: CameraPositionState? = null
    val cameraPositionState: CameraPositionState
        get() = _cameraPositionState ?: run {
            val initialState = rememberCameraPositionState(
                initialPosition = CameraPosition.fromLatLngZoom(LatLng(39.9042, 116.4074), 10f)
            )
            _cameraPositionState = initialState
            initialState
        }

    // MapScreen销毁时调用,清空状态引用
    fun clearState() {
        _cameraPositionState = null
    }
}
  1. 在MapScreen中使用:
@Composable
fun MapScreen() {
    val viewModel = viewModel<MapViewModel>()
    val cameraPositionState = viewModel.cameraPositionState

    // 页面销毁时清空ViewModel中的状态引用
    DisposableEffect(Unit) {
        onDispose {
            viewModel.clearState()
        }
    }

    GoogleMap(
        cameraPositionState = cameraPositionState
    ) {
        // 地图内容
    }
}

注意事项

  • 确保使用最新版maps-compose依赖(如com.google.maps.android:maps-compose:4.3.2及以上),部分旧版本的状态绑定bug已在新版本修复。
  • 避免直接在全局(如MainActivity)持有CameraPositionState,这种方式极易引发多组件绑定冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 12:35:02