android-maps-compose icon indicating copy to clipboard operation
android-maps-compose copied to clipboard

Polyline doesn't recompose when points change

Open PeterAttardo opened this issue 2 years ago • 9 comments

Environment details

Android API 26 com.google.maps.android:maps-compose:2.1.0

Steps to reproduce

  1. Create a map with a MutableStateList of points
  2. Use the points to draw markers and a polyline between them
  3. Add functionality to add or remove points from the list
  4. Observe that the markers update, but the polyline does not

Code example

@Composable
fun MapScreen(){
    val waypoints = remember{ mutableStateListOf<LatLng>()}
    Map(waypoints) {
        waypoints.add(it)
    }
}

@Composable
private fun Map(
    waypoints: List<LatLng>,
    modifier: Modifier = Modifier,
    onMapClicked: (latlng: LatLng) -> Unit
){
    GoogleMap(
        modifier = modifier,
        onMapClick = onMapClicked,
    ){
        waypoints.forEach {
            Marker(state = MarkerState(position = it))
        }
        Polyline(waypoints)
    }
}

PeterAttardo avatar Apr 29 '22 23:04 PeterAttardo

@PeterAttardo Please take a moment to fill out this short survey. Thank you!

This is an automated message, feel free to ignore.

jpoehnelt avatar Apr 29 '22 23:04 jpoehnelt

@PeterAttardo Thank you for opening this issue. 🙏 Please check out these other resources that might be applicable:

This is an automated message, feel free to ignore.

jpoehnelt avatar Apr 29 '22 23:04 jpoehnelt

This should be fixed. But a workaround would be to use a mutableStateOf instead. So:

@Composable
fun MapScreen(){
    val waypoints by remember{ mutableStateOf<List<LatLng>>()}
    Map(waypoints) {
        waypoints = waypoints + it
    }
}

arriolac avatar May 11 '22 18:05 arriolac

@arriolac Was this a bug in maps-compose or Compose itself? And specifically handling mutableStateListOf()?

I think the other potential catch here is to make sure you're using mutableStateOf<List<LatLng>>() and not mutableStateOf<ArrayList<LatLng>>(), similar to my comment here regarding recomposition and mutable collections - https://github.com/googlemaps/android-maps-compose/issues/91#issuecomment-1105229716.

barbeau avatar May 11 '22 18:05 barbeau

I believe the issue might be between the interaction of mutableStateListOf and a ComposeNode's Updater. Because Polyline as currently implemented should work. I've opened an issue in the public issue tracker for Compose here: https://issuetracker.google.com/issues/232271525

arriolac avatar May 11 '22 19:05 arriolac

Is the question still open? Help me. the last Polyline is not updated, but markers are drawn according to the route.

@Composable
fun MapScreen(){
  val path  = chvm.pathResult.observeAsState()
    var waypoints by remember{ mutableStateOf<List<LatLng>>(value = listOf())}

    if(path.value?.path?.size != null){
        Map(path.value?.path!!) {
            waypoints = waypoints + it
        }
    }
}

@Composable
private fun Map(
    waypoints: List<LatLng>,
    modifier: Modifier = Modifier,
    onMapClicked: (latlng: LatLng) -> Unit
){
    GoogleMap(
        modifier = modifier,
        onMapClick = onMapClicked,
    ){
        waypoints.forEach {
            Marker(state = MarkerState(position = it))
        }
        Polyline(waypoints)
    }
}

Screenshot_202

Sergiyss avatar Aug 16 '22 07:08 Sergiyss

I found the same issue:

But when I was investigating the problem, I notice that when show the list in logcat.

D/MainActivity:androidx.compose.runtime.snapshots.SnapshotStateList@f1e2953

In this case we don't send the list in the end.

TrackerLocationTheme {
    val cameraPositionState = rememberCameraPositionState()
    val waypoints = remember { mutableStateListOf<LatLng>() }

    LocationService.lastLocation?.let {
        waypoints.add(it)
    }

    Scaffold(
        topBar = {
            TopAppBar(title = {
                Text(text = getString(R.string.app_name))
            })
        },
    ) { paddingValues ->
        GoogleMap(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues),
            cameraPositionState = cameraPositionState,
            properties = MapProperties(
                isMyLocationEnabled = true,
                mapStyleOptions = MapStyleOptions.loadRawResourceStyle(
                    LocalContext.current,
                    R.raw.map_style
                )
            ),
        ) {
            Polyline(points = waypoints.toList())
        }
    }
}

if you transform that toList, it will works fine.

weslleystos avatar Mar 15 '23 02:03 weslleystos

I found the same issue:

But when I was investigating the problem, I notice that when show the list in logcat.

D/MainActivity:androidx.compose.runtime.snapshots.SnapshotStateList@f1e2953

In this case we don't send the list in the end.

TrackerLocationTheme {
    val cameraPositionState = rememberCameraPositionState()
    val waypoints = remember { mutableStateListOf<LatLng>() }

    LocationService.lastLocation?.let {
        waypoints.add(it)
    }

    Scaffold(
        topBar = {
            TopAppBar(title = {
                Text(text = getString(R.string.app_name))
            })
        },
    ) { paddingValues ->
        GoogleMap(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues),
            cameraPositionState = cameraPositionState,
            properties = MapProperties(
                isMyLocationEnabled = true,
                mapStyleOptions = MapStyleOptions.loadRawResourceStyle(
                    LocalContext.current,
                    R.raw.map_style
                )
            ),
        ) {
            Polyline(points = waypoints.toList())
        }
    }
}

if you transform that toList, it will works fine.

This works! Thank you.

Ruineie avatar Apr 05 '23 08:04 Ruineie

This still happens at least in 4.2.0. I need to test in the latest. Lucky I found this issue otherwise I would've lost a good time going mad over this

marcportabellanavarro avatar Apr 04 '24 13:04 marcportabellanavarro