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
相关产品推荐
相关产品推荐

