googlemaps / android-maps-compose

Jetpack Compose composables for the Maps SDK for Android
https://developers.google.com/maps/documentation/android-sdk/maps-compose
Apache License 2.0
1.14k stars 135 forks source link

java.util.NoSuchElement ComposeUiClusterRenderer.getDescriptorForCluster #393

Open HannesSundin opened 1 year ago

HannesSundin commented 1 year ago

Environment details

"com.google.maps.android:maps-compose:2.14.0" "com.google.maps.android:maps-compose-utils:2.11.0"

Steps to reproduce

  1. Clustering Composable with many items
  2. ClusterItemContent and ClusterContent uses Images with Vector Drawables

Stack trace

   java.util.NoSuchElementException: Collection contains no element matching the predicate.
                                                                at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer.getDescriptorForCluster(ClusterRenderer.kt:234)
                                                                at com.google.maps.android.clustering.view.DefaultClusterRenderer.onBeforeClusterRendered(DefaultClusterRenderer.java:913)
                                                                at com.google.maps.android.clustering.view.DefaultClusterRenderer$CreateMarkerTask.perform(DefaultClusterRenderer.java:1073)
                                                                at com.google.maps.android.clustering.view.DefaultClusterRenderer$CreateMarkerTask.access$2400(DefaultClusterRenderer.java:1021)
                                                                at com.google.maps.android.clustering.view.DefaultClusterRenderer$MarkerModifier.performNextTask(DefaultClusterRenderer.java:738)
                                                                at com.google.maps.android.clustering.view.DefaultClusterRenderer$MarkerModifier.handleMessage(DefaultClusterRenderer.java:707)
                                                                at android.os.Handler.dispatchMessage(Handler.java:106)
                                                                at android.os.Looper.loopOnce(Looper.java:226)
                                                                at android.os.Looper.loop(Looper.java:313)
                                                                at android.app.ActivityThread.main(ActivityThread.java:8747)
                                                                at java.lang.reflect.Method.invoke(Native Method)
                                                                at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
                                                                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
wangela commented 1 year ago

If you would like to upvote the priority of this issue, please comment below or react on the original post above with :+1: so we can see what is popular when we triage.

@HannesSundin Thank you for opening this issue. 🙏 Please check out these other resources that might help you get to a resolution in the meantime:

This is an automated message, feel free to ignore.

kikoso commented 1 year ago

@HannesSundin , can you provide a code snippet showcasing your case? Thanks!

HannesSundin commented 1 year ago
val context = LocalContext.current
  val density = LocalDensity.current
  val coroutineScope = rememberCoroutineScope()
  val cameraPositionState = rememberCameraPositionState {
    position = initialCameraPosition
  }

  GoogleMap(
    onMapLoaded = {
        setZoomLevel(cameraPositionState.getZoomLevel())
        setBounds(cameraPositionState.getBounds())
        onMapReady()
    },
    cameraPositionState = cameraPositionState,
    uiSettings = MapUiSettings(
        myLocationButtonEnabled = true,
        zoomControlsEnabled = false,
        mapToolbarEnabled = false,
        compassEnabled = false
    ),
    contentPadding = PaddingValues(bottom = sheetPeekHeight + 32.dp),
    properties = MapProperties(
        isBuildingEnabled = false,
        isMyLocationEnabled = true,
        isIndoorEnabled = false,
        isTrafficEnabled = false,
        mapStyleOptions = MapStyleOptions.loadRawResourceStyle(
            context,
            R.raw.map_style_night
        )
    ),
    ) {

    LaunchedEffect(cameraPositionState.isMoving) {
        if (!cameraPositionState.isMoving) {
            setBounds(cameraPositionState.getBounds())
            setZoomLevel(cameraPositionState.getZoomLevel())
        }
    }

    LaunchedEffect(zoomToBounds) {
        zoomToBounds?.let {
            cameraPositionState.animate(it.toCameraUpdate(density), 500)
        }
    }

    val markerInfoWindowState = rememberMarkerState()
    var clickedIcon: Pair<String?, String?>? by remember {
        mutableStateOf(null)
    }
    mailboxes.forEach {
        Marker(
            state = MarkerState(it.mailbox.location),
            icon = context.bitmapDescriptorFromVector(R.drawable.ic_map_pin),
            snippet = it.mailbox.countryCode,
            tag = MARKER_MAILBOX,
            title = it.mailbox.mailboxId,
            visible = true,
            zIndex = 0.0f,
            onClick = {
                clickedIcon = it.title to it.snippet
                markerInfoWindowState.position = it.position
                true
            },
        )
    }
    Clustering(
        items = items,
        onClusterClick = { cluster ->
            val positions = cluster.items.map { it.position }
            val bounds = LatLngBounds.builder().apply {
                positions.forEach { include(it) }
            }.build()
            val cameraUpdate = bounds.toCameraUpdate(density = density)

            coroutineScope.launch {
                cameraPositionState.animate(
                    cameraUpdate,
                    context.resources.getInteger(android.R.integer.config_longAnimTime)
                )
            }
            true
        },
        onClusterItemInfoWindowClick = {
            onLocationClicked(
                Id(
                    id = it.title,
                    countryCode = it.countryCode,
                    type = if (it.distributionPointType.isServicePoint()) {
                        LocationId.Type.SP
                    } else LocationId.Type.PB
                )
            )
        },
        onClusterItemClick = {
            clickedIcon = it.title to it.snippet
            markerInfoWindowState.position = it.position
            markerInfoWindowState.showInfoWindow()
            true
        },
        clusterContent = {
            Image(
                modifier = Modifier.wrapContentSize(),
                painter = painterResource(
                    R.drawable.graphics_map_pin_cluster
                ),
                contentDescription = null,
            )
        },
        clusterItemContent = {
            Image(
                modifier = Modifier.wrapContentSize(),
                painter = painterResource(
                    it.getPinResource(MapMode.Default),
                ),
                contentDescription = null,
            )
        }
    )

    if (clickedIcon != null) {
        MarkerInfoWindow(
            state = markerInfoWindowState,
            icon = context.bitmapDescriptorFromVector(R.drawable.ic_map_pin),
            title = clickedIcon!!.first,
            snippet = clickedIcon!!.second,
            zIndex = Float.MAX_VALUE,
            onInfoWindowClick = {

            }
        ) {
            InfoWindow(title = it.title, snippet = it.snippet)
        }
    }
  }

Its hard to reproduce it but here is the code i was using, it didnt happen that many times but I got one crash at least