Compose中使用MapBox调用flyTo()触发MapInitOptions修改异常求助
MapBox Jetpack Compose:flyTo触发Mutating MapInitOptions异常的解决方法
问题场景
在Jetpack Compose中使用MapBox,调用mapViewportState.flyTo()设置地图目标位置时,抛出Mutating MapInitOptions during composition is not allowed异常。移除mapInitOptionsFactory = { MapInitOptions(...) }配置后功能正常,但会丢失自定义地图样式。
原代码:
val mapViewportState = rememberMapViewportState LaunchedEffect(key1 = userInitialLocation) { userInitialLocation?.let { userLocation -> mapViewportState.flyTo( cameraOptions = mapViewportState.cameraState.toCamera .center( Point.fromLngLat( userLocation.longitude, userLocation.latitude ) ) .zoom(16.0) .build() ) } } val context = LocalContext.current if (isLocationPermissionGranted) { MapboxMap( modifier = Modifier.fillMaxSize(), mapViewportState = mapViewportState, mapInitOptionsFactory = { // 注释掉这段就正常 MapInitOptions( context = context, styleUri = Style.DARK, ) } ) }
错误日志
Error was captured in composition while live edit was enabled. java.lang.IllegalStateException: Mutating MapInitOptions during composition is not allowed. at com.mapbox.maps.extension.compose.internal.MapboxMapNodeKt$MapboxMapComposeNode$2$1.invoke(MapboxMapNode.kt:136) at com.mapbox.maps.extension.compose.internal.MapboxMapNodeKt$MapboxMapComposeNode$2$1.invoke(MapboxMapNode.kt:135) at androidx.compose.runtime.ComposerImpl$apply$operation$1.invoke(Composer.kt:1712) at androidx.compose.runtime.ComposerImpl$apply$operation$1.invoke(Composer.kt:1710) at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:818) at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:849) at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:625) at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:537) at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:41) at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109) at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41) at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1229) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239) at android.view.Choreographer.doCallbacks(Choreographer.java:899) at android.view.Choreographer.doFrame(Choreographer.java:827) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214) at android.os.Handler.handleCallback(Handler.java:942) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.app.ActivityThread.main(ActivityThread.java:7872) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
解决方法
将MapInitOptions的创建用remember包裹,确保重组时复用同一个实例,避免触发MapBox的检查逻辑:
val mapViewportState = rememberMapViewportState() LaunchedEffect(key1 = userInitialLocation) { userInitialLocation?.let { userLocation -> mapViewportState.flyTo( cameraOptions = mapViewportState.cameraState.toCameraOptions() .center( Point.fromLngLat( userLocation.longitude, userLocation.latitude ) ) .zoom(16.0) .build() ) } } val context = LocalContext.current // 用remember缓存MapInitOptions实例 val mapInitOptions = remember { MapInitOptions( context = context, styleUri = Style.DARK, ) } if (isLocationPermissionGranted) { MapboxMap( modifier = Modifier.fillMaxSize(), mapViewportState = mapViewportState, mapInitOptionsFactory = { mapInitOptions } ) }
原因说明
MapBox的Compose组件不允许在重组过程中修改或替换MapInitOptions实例。原代码中每次重组都会通过mapInitOptionsFactory创建新的MapInitOptions,触发了内部的非法状态检查。用remember包裹后,实例仅在首次组合时创建,后续重组复用同一实例,符合MapBox的约束要求。
内容的提问来源于stack exchange,提问作者user924
相关产品推荐
相关产品推荐

