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

Jetpack Compose点击底部导航项后地图标记丢失问题求助

解决Jetpack Compose中底部导航重选后Google Map标记丢失的问题

问题根源

重新点击底部导航项时,即便配置了saveState = true和restoreState = true,Composable的remember状态仍会随页面销毁而重置——因为remember的作用域仅绑定当前Composable实例的生命周期,页面重建时会重新执行remember代码块,导致之前的地图相机位置、标记状态全部丢失。

解决方案:用ViewModel持久化地图状态

ViewModel的生命周期独立于Composable,只要在同一个导航图作用域内,ViewModel实例会被保留,从而稳定持久化地图的相机位置和标记状态。

1. 创建MapViewModel管理状态

import androidx.lifecycle.ViewModel
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

class MapViewModel : ViewModel() {
    // 保存相机位置
    private val _cameraPosition = MutableStateFlow<CameraPosition?>(null)
    val cameraPosition: StateFlow<CameraPosition?> = _cameraPosition

    // 保存标记状态
    private val _markerState = MutableStateFlow<MarkerState?>(null)
    val markerState: StateFlow<MarkerState?> = _markerState

    // 初始化地图状态(仅第一次调用)
    fun initMap(initialLatLng: LatLng) {
        if (_cameraPosition.value == null) {
            _cameraPosition.value = CameraPosition.fromLatLngZoom(initialLatLng, 15f)
            _markerState.value = MarkerState(position = initialLatLng)
        }
    }

    // 更新相机位置(监听地图相机变化时调用)
    fun updateCameraPosition(newPosition: CameraPosition) {
        _cameraPosition.value = newPosition
    }
}

2. 修改LocationMap Composable,绑定ViewModel

@Composable
fun LocationMap(
    latLng: LatLng,
    viewModel: MapViewModel = viewModel() // 默认获取导航图作用域的ViewModel实例
) {
    // 仅第一次进入时初始化地图状态
    viewModel.initMap(latLng)

    val mapProperties by remember {
        mutableStateOf(
            MapProperties(maxZoomPreference = 30f, minZoomPreference = 5f)
        )
    }
    val mapUiSettings by remember {
        mutableStateOf(
            MapUiSettings(mapToolbarEnabled = false)
        )
    }

    // 从ViewModel收集状态
    val cameraPosition by viewModel.cameraPosition.collectAsState()
    val markerState by viewModel.markerState.collectAsState()

    cameraPosition?.let { camPos ->
        val cameraState = rememberCameraPositionState {
            position = camPos
        }

        // 监听相机位置变化,同步到ViewModel
        LaunchedEffect(cameraState) {
            snapshotFlow { cameraState.position }
                .collect { viewModel.updateCameraPosition(it) }
        }

        GoogleMap(
            properties = mapProperties,
            uiSettings = mapUiSettings,
            cameraPositionState = cameraState
        ) {
            markerState?.let { marker ->
                Marker(
                    state = marker,
                    title = "Title"
                )
            }
        }
    }
}

3. 验证导航配置

确保底部导航的目的地属于同一个导航图,这样viewModel()会始终获取到同一个实例。你现有导航代码中的saveState和restoreState配置可以保留,但核心状态管理交给ViewModel即可。

额外说明

  • 如果需要动态添加多个标记,可在ViewModel中维护MutableStateFlow<List<MarkerState>>,统一管理所有标记状态。
  • 避免用NavBackStackEntry的savedStateHandle保存复杂状态(如CameraPosition),序列化/反序列化可能出现异常,ViewModel是更可靠的选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 20:23:08