When I insert a marker into the marker list it crashes
it seems that when insert a marker, it call a wrong marker.onAttached
or how can I insert a marker to an ordered list
version 2.7.0
Steps to reproduce
click the below Insert button
Code example
val markers = remember {
mutableStateListOf(MarkerState(singapore), MarkerState(singapore3))
}
val path = markers.map { it.position }
// ...
GoogleMap(
modifier = modifier,
cameraPositionState = cameraPositionState,
properties = mapProperties,
uiSettings = uiSettings,
onMapLoaded = onMapLoaded,
) {
for (marker in markers) {
Marker(
state = marker,
title = "Marker in Singapore"
)
}
Polyline(points = path)
}
// ...
MapButton(
text = "Insert",
onClick = {
val lat1 = singapore.latitude
val lng1 = singapore.longitude
val lat2 = singapore3.latitude
val lng2 = singapore3.longitude
markers.add(
1,
MarkerState(
position = LatLng(
Random.nextDouble(min(lat1, lat2), max(lat1, lat2)),
Random.nextDouble(min(lng1, lng2), max(lng1, lng2))
)
)
)
},
modifier = Modifier.testTag("insert"),
)
Stack trace
E/AndroidRuntime: FATAL EXCEPTION: main
Process: app.xigu.maps.compose, PID: 22658
java.lang.IllegalStateException: MarkerState may only be associated with one Marker at a time.
at com.google.maps.android.compose.MarkerState.setMarker$maps_compose_debug(Marker.kt:88)
at com.google.maps.android.compose.MarkerNode.onAttached(Marker.kt:46)
at com.google.maps.android.compose.MapApplier.insertBottomUp(MapApplier.kt:53)
at com.google.maps.android.compose.MapApplier.insertBottomUp(MapApplier.kt:34)
at androidx.compose.runtime.ComposerImpl$createNode$3.invoke(Composer.kt:1548)
at androidx.compose.runtime.ComposerImpl$createNode$3.invoke(Composer.kt:1543)
at androidx.compose.runtime.ComposerImpl$recordInsert$2.invoke(Composer.kt:3395)
at androidx.compose.runtime.ComposerImpl$recordInsert$2.invoke(Composer.kt:3392)
at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:782)
at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:813)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:526)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:454)
at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34)
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:1350)
at android.view.Choreographer.doCallbacks(Choreographer.java:1149)
at android.view.Choreographer.doFrame(Choreographer.java:1040)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1333)
Can you try using a mutableStateOf instead of a mutableStateListOf? Otherwise, you can fix this issue by appending to the end of markers rather than inserting at position 1.
Can you try using a
mutableStateOfinstead of amutableStateListOf? Otherwise, you can fix this issue by appending to the end ofmarkersrather than inserting at position 1.
mutableStateOf behaves the same as mutableStateListOf.
My requirement is to insert one or more points between two points to form a polyline.
And the start and end points are fixed
I believe this relates to https://github.com/googlemaps/android-maps-compose/issues/149 (bullet point 2). Maintaining lists of markers in the current maps-compose API is odd and complex in the general case. The API suggests hoisting MarkerState into an intermediate data model of sorts, which does not really work.
@MankinChung: what you may want to do until #149 is addressed: do not actually hoist MarkerState into your markers list, but only maintain coordinate pairs in your list. Create MarkerState only in the GoogleMap block, transforming (observing) your list of coordinate pairs to Markers in your for loop. This will recreate Markers when the list changes, but you get maintainable code.
You can improve on this pattern by indexing your list iteration with the Compose key() function, effectively skipping most Marker recreations. You need to add some kind of unique list element key for this to work, which can be as simple as creating a new key object via Any(); you'd create the key when inserting a new list element.
@bubenheimer Thanks for your help,key() function works for me,although it will recreation the markers after the insert index.
Marker recreation is surprising, but could possibly be caused by something maps-compose does behind the scenes, maybe a bug. Watch out for these:
- Keep most for loop iterations (except the inserted one) from recomposing and tuck your for loop block fully inside the key lambda.
- Even with recomposition, as long as you
rememberMarkerStatein each loop iteration and you key off the iterations correctly, Markers should not be recreated.
All you're doing with this is leveraging standard Compose functionality to keep maps-compose from seeing and touching what you're doing. However, maps-compose can interpret the Compose tree any way it wants, so who knows.
I'm not seeing the recreation mentioned. Closing as a wontfix as keying the markers is a good practice. Will reopen the issue if there's still a problem.