How to refresh cluster markers on a map with Jetpack Composite?

Viewed 664

In my application I am showing a map with different zones marked using the clusters so that the closest locations are grouped. But I have a problem. When I modify some marker (using for example search filters by name) the markers are not always updated. Sometimes the new ones are painted, but almost always the old ones stay. I've tried clearing the markers before adding them back, but it doesn't work. This is my code:

@Composable
fun MyMap(
    locations: State<LocationData>
) {

    lateinit var clusterManager: ClusterManager<LocationClusterItem>
    val mapView = rememberMapViewWithLifeCycle()
    val localContext = LocalContext.current
    
    Column(
        modifier = Modifier
            .background(Color.White)
    ) {
        AndroidView(
            {
                mapView
            }
        ) {

            mapView.getMapAsync {
                val map = it
                map.uiSettings.isZoomControlsEnabled = false
                clusterManager = ClusterManager(localContext, map)

                clusterManager.clearItems()
                clusterManager.cluster()

                map.setOnCameraIdleListener(clusterManager)
                map.setOnMarkerClickListener(clusterManager)

                for (location in locations.value.sites) {
                    clusterManager.addItem(IncidentClusterItem(location.lat, location.lon, location.street, location.info))
                }

                clusterManager.cluster()

                map.moveCamera(
                    CameraUpdateFactory.newLatLngZoom(
                        LatLng(50.00000000000000, -10.000000000000000),
                        12f
                    )
                )
                map.mapType = GoogleMap.MAP_TYPE_HYBRID
            }

        }
    }

}

How can I make the markers on the map update correctly?

2 Answers

Just a guess, but I assume state reads inside mapView.getMapAsync(callback) do not get tracked. What is driving the calls to update?

Can you update state externally when the markers change and then read them from the update lambda before you call mapViuw.getAsync?

Specifically from the docs

AndroidView(
    modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree
    factory = { context ->
        // Creates custom view
        CustomView(context).apply {
            // Sets up listeners for View -> Compose communication
            myView.setOnClickListener {
                selectedItem.value = 1
            }
        }
    },
    update = { view ->
        // View's been inflated or state read in this block has been updated
        // Add logic here if necessary

        // As selectedItem is read here, AndroidView will recompose
        // whenever the state changes
        // Example of Compose -> View communication
        view.coordinator.selectedItem = selectedItem.value
    }

I think the state read needs to be directly in the update block.

In order to have your cluster markers list be observable you have to call toList() on your list. It has something to do with how clusterManager accesses the list and toList is the proper way to do that.

Update: Looks like compose-maps will support clustering via a workaround for the meantime if you want to move away from AndroidView. https://github.com/googlemaps/android-maps-compose/pull/140

Related