mapbox / mapbox-maps-android

Interactive, thoroughly customizable maps in native Android powered by vector tiles and OpenGL.
https://www.mapbox.com/mobile-maps-sdk
Other
462 stars 131 forks source link

Drawing route line with LineLayer and geoJsonSource crashes app #2380

Open s23210 opened 3 months ago

s23210 commented 3 months ago

Environment

When I try to draw LineLayer from directions API geoJsonSource It seems that LineLayer doesn't work

2024-05-21 11:00:39.912 22680-22680 AndroidRuntime          pl.pjatk.safetrail                   E  FATAL EXCEPTION: main
                                                                                                    Process: pl.pjatk.safetrail, PID: 22680
                                                                                                    java.lang.NoSuchMethodError: No virtual method removeStyleSourceUnchecked(Ljava/lang/String;)Lcom/mapbox/bindgen/Expected; in class Lcom/mapbox/maps/MapboxMap; or its super classes (declaration of 'com.mapbox.maps.MapboxMap' appears in /data/data/pl.pjatk.safetrail/code_cache/.overlay/base.apk/classes17.dex)
                                                                                                        at com.mapbox.maps.extension.compose.style.sources.SourceState.removeSource(SourceState.kt:323)
                                                                                                        at com.mapbox.maps.extension.compose.style.sources.SourceState.access$removeSource(SourceState.kt:51)
                                                                                                        at com.mapbox.maps.extension.compose.style.sources.SourceState$collectBuilderProperty$2.emit(SourceState.kt:288)
                                                                                                        at com.mapbox.maps.extension.compose.style.sources.SourceState$collectBuilderProperty$2.emit(SourceState.kt:270)
                                                                                                        at kotlinx.coroutines.flow.StateFlowImpl.collect(StateFlow.kt:396)
                                                                                                        at com.mapbox.maps.extension.compose.style.sources.SourceState.collectBuilderProperty(SourceState.kt:270)
                                                                                                        at com.mapbox.maps.extension.compose.style.sources.SourceState.access$collectBuilderProperty(SourceState.kt:51)
                                                                                                        at com.mapbox.maps.extension.compose.style.sources.SourceState$launchCollectProperty$1.invokeSuspend(SourceState.kt:263)
                                                                                                        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
                                                                                                        at kotlinx.coroutines.EventLoop.processUnconfinedEvent(EventLoop.common.kt:68)
                                                                                                        at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:375)
                                                                                                        at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
                                                                                                        at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25)
                                                                                                        at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110)
                                                                                                        at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
                                                                                                        at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
                                                                                                        at kotlinx.coroutines.BuildersKt.launch(Unknown Source:1)
                                                                                                        at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
                                                                                                        at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1)
                                                                                                        at com.mapbox.maps.extension.compose.style.sources.SourceState.launchCollectPropertyFlows(SourceState.kt:245)
                                                                                                        at com.mapbox.maps.extension.compose.style.sources.SourceState.attachTo(SourceState.kt:169)
                                                                                                        at com.mapbox.maps.extension.compose.style.sources.SourceState.attachToLayer$extension_compose_release(SourceState.kt:125)
                                                                                                        at com.mapbox.maps.extension.compose.style.layers.internal.LayerNode.attachSource(LayerNode.kt:52)
                                                                                                        at com.mapbox.maps.extension.compose.style.layers.internal.LayerNode.access$attachSource(LayerNode.kt:18)
                                                                                                        at com.mapbox.maps.extension.compose.style.layers.internal.LayerNode$addLayer$2$1.emit(LayerNode.kt:123)
                                                                                                        at com.mapbox.maps.extension.compose.style.layers.internal.LayerNode$addLayer$2$1.emit(LayerNode.kt:113)
                                                                                                        at kotlinx.coroutines.flow.SharedFlowImpl.collect$suspendImpl(SharedFlow.kt:382)
                                                                                                        at kotlinx.coroutines.flow.SharedFlowImpl.collect(Unknown Source:0)
                                                                                                        at kotlinx.coroutines.flow.ReadonlySharedFlow.collect(Unknown Source:2)
                                                                                                        at com.mapbox.maps.extension.compose.style.layers.internal.LayerNode$addLayer$2.invokeSuspend(LayerNode.kt:113)
                                                                                                        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
                                                                                                        at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
                                                                                                        at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
                                                                                                        at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:68)
                                                                                                        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1397)
                                                                                                        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1408)
                                                                                                        at android.view.Choreographer.doCallbacks(Choreographer.java:1008)
2024-05-21 11:00:39.913 22680-22680 AndroidRuntime          pl.pjatk.safetrail                   E      at android.view.Choreographer.doFrame(Choreographer.java:934)
                                                                                                        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1382)
                                                                                                        at android.os.Handler.handleCallback(Handler.java:959)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:100)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:232)
                                                                                                        at android.os.Looper.loop(Looper.java:317)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8501)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:878)
                                                                                                        Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [CoroutineName(SourceStateMapboxMapScope_COMPOSE_SOURCE_ID_geojson_b3cf30b2-6fe2-475b-b613-e6695e7920a4), StandaloneCoroutine{Cancelling}@e716452, Dispatchers.Main.immediate]
    @Composable
    fun MapboxMapComponent() {
        val locationUtilities = LocationUtilities(context)

        var points by remember {
            mutableStateOf<List<Point>>(listOf())
        }

        var pointsWithLocation = listOf(
            locationUtilities.retrieveCurrentLocationFromSession()
                ?.let { Point.fromLngLat(it.second, it.first) }) + points

        var routeLine by remember {
            mutableStateOf<LineString?>(null)
        }

        val mapViewportState = rememberMapViewportState {
            setCameraOptions {
                zoom(10.0)
                locationUtilities.retrieveCurrentLocationFromSession()?.let {
                    center(Point.fromLngLat(it.second, it.first))
                }
                pitch(0.0)
                bearing(0.0)
            }
        }

        val geoJsonSource = rememberGeoJsonSourceState {
            lineMetrics = LineMetrics(true)
        }

        LaunchedEffect(points) {
            updateCurrentLocation(locationUtilities, points) { newPoints ->
                pointsWithLocation = newPoints
            }

            fetchRoute(pointsWithLocation) {
                routeLine = it
            }
        }

        if (points.isNotEmpty()) {
            focusOnRouteLine(mapViewportState, routeLine)
        }

        LaunchedEffect(routeLine) {
            routeLine?.let {
                geoJsonSource.data = GeoJSONData(it)
            }
        }

        MapboxMap(
            modifier = Modifier.fillMaxSize(),
            style = { SelectStyle(routeLine, points) },
            mapViewportState = mapViewportState,
            logo = {},
            attribution = {},
            compass = {
                Compass(
//                TODO: Adjust compass position
                    modifier = Modifier.padding(bottom = 24.dp),
                    alignment = Alignment.BottomEnd
                )
            },
            onMapLongClickListener = { point ->
                points = points.toMutableList().apply { add(point) }
                WeatherConnector().checkWeather(
                    Pair(point.latitude(), point.longitude()),
                    context
                ) { isSuccess, weather ->
                    if (isSuccess && weather.isNotEmpty()) {
                        Handler(Looper.getMainLooper()).post {
                            Toast.makeText(
                                context,
                                String.format(
                                    Locale.ENGLISH,
                                    pointStringFormat,
                                    point.latitude(),
                                    point.longitude()
                                ) + " " +
                                        "${weather[0].time}, ${weather[0].weatherCode}",
                                Toast.LENGTH_LONG
                            ).show()
                        }
                    } else {
                        Handler(Looper.getMainLooper()).post {
                            Toast.makeText(
                                context,
                                "Weather data not available",
                                Toast.LENGTH_SHORT
                            ).show()
                        }
                    }
                }
                true
            }
        ) {
            MapEffect(Unit) { mapView ->
                mapView.location.updateSettings {
                    setLocationPuck(createDefault2DPuck(withBearing = true))
                    setPuckBearingEnabled(true)
                    setPulsingEnabled(true)
                    setPuckBearing(PuckBearing.HEADING)
                    setEnabled(true)
                }
            }
            CreatePointAnnotationGroupForRoutePlanning(
                points = points,
                onClick = { clickedPoint ->
                    points = points.toMutableList().apply { remove(clickedPoint.point) }
                    true
                }
            )
        }
    }

    @OptIn(MapboxExperimental::class)
    @Composable
    private fun SelectStyle(
        routeLine: LineString?,
        points: List<Point>
    ) {
        if (routeLine != null && points.isNotEmpty()) {
            NavigationStyle(routeLine, 0.5)
        } else {
            MapStyle(style = styleUrl)
        }
    }

    @SuppressLint("IncorrectNumberOfArgumentsInExpression")
    @OptIn(MapboxExperimental::class)
    @MapboxStyleComposable
    @Composable
    private fun NavigationStyle(routeLine: LineString?, progress: Double) {
//        TODO: add progress
        val geoJsonSource = rememberGeoJsonSourceState {
            lineMetrics = LineMetrics(true)
        }

        LaunchedEffect(routeLine) {
            routeLine?.let {
                geoJsonSource.data = GeoJSONData(it)
            }
        }

        GenericStyle(
            style = styleUrl,

//            layerPositionedContent = layerPositionedContent {
//                aboveLayer("land") {
//                    LineLayer(
//                        sourceState = geoJsonSource,
//                        lineTrimOffset = LineTrimOffset(listOf(0.0, progress)),
//                        lineWidth = LineWidth(
//                            interpolate {
//                                exponential {
//                                    literal(1.5)
//                                }
//                                zoom()
//                                stop {
//                                    literal(10)
//                                    product(7.0, 1.0)
//                                }
//                                stop {
//                                    literal(14.0)
//                                    product(10.5, 1.0)
//                                }
//                                stop {
//                                    literal(16.5)
//                                    product(15.5, 1.0)
//                                }
//                                stop {
//                                    literal(19.0)
//                                    product(24.0, 1.0)
//                                }
//                                stop {
//                                    literal(22.0)
//                                    product(29.0, 1.0)
//                                }
//                            }
//                        ),
//                        lineCap = LineCap.ROUND,
//                        lineJoin = LineJoin.ROUND,
//                        lineGradient = LineGradient(
//                            interpolate {
//                                linear()
//                                lineProgress()
//                                stop {
//                                    literal(0)
//                                    rgba(47.0, 122.0, 198.0, 1.0)
//                                }
//                                stop {
//                                    literal(1.0)
//                                    rgba(47.0, 122.0, 198.0, 1.0)
//                                }
//                            }
//                        )
//                    )
//                }
//            }
//            slotsContent = slotsContent {
////                mapOf(
////                    "lineLayer1" to {
//                if (routeLine != null) {
//                    slot("top") {
//                        LineLayer(
//                            sourceState = geoJsonSource,
//                            lineTrimOffset = LineTrimOffset(listOf(0.0, progress)),
//                            lineWidth = LineWidth(
//                                interpolate {
//                                    exponential {
//                                        literal(1.5)
//                                    }
//                                    zoom()
//                                    stop {
//                                        literal(10)
//                                        product(7.0, 1.0)
//                                    }
//                                    stop {
//                                        literal(14.0)
//                                        product(10.5, 1.0)
//                                    }
//                                    stop {
//                                        literal(16.5)
//                                        product(15.5, 1.0)
//                                    }
//                                    stop {
//                                        literal(19.0)
//                                        product(24.0, 1.0)
//                                    }
//                                    stop {
//                                        literal(22.0)
//                                        product(29.0, 1.0)
//                                    }
//                                }
//                            ),
//                            lineCap = LineCap.ROUND,
//                            lineJoin = LineJoin.ROUND,
//                            lineGradient = LineGradient(
//                                interpolate {
//                                    linear()
//                                    lineProgress()
//                                    stop {
//                                        literal(0)
//                                        rgba(47.0, 122.0, 198.0, 1.0)
//                                    }
//                                    stop {
//                                        literal(1.0)
//                                        rgba(47.0, 122.0, 198.0, 1.0)
//                                    }
//                                }
//                            )
//                        )
//                    }
//                }
////                    }
////                )
//            }

        )
    }`

Both ways in comments won't work and app crashes. It worked before I updated mapbox from 11.3.0 to 11.4.0-rc.1 when i used:
`            slots = mapOf(
                "lineLayer1" to {
                    if (routeLine != null) {
                        LineLayer(
                            sourceState = geoJsonSource,
                            lineWidth = LineWidth(
                                interpolate {
                                    exponential {
                                        literal(1.5)
                                    }
                                    zoom()
                                    stop {
                                        literal(10)
                                        product(7.0, 1.0)
                                    }
                                    stop {
                                        literal(14.0)
                                        product(10.5, 1.0)
                                    }
                                    stop {
                                        literal(16.5)
                                        product(15.5, 1.0)
                                    }
                                    stop {
                                        literal(19.0)
                                        product(24.0, 1.0)
                                    }
                                    stop {
                                        literal(22.0)
                                        product(29.0, 1.0)
                                    }
                                }
                            ),
                            lineCap = LineCap.ROUND,
                            lineJoin = LineJoin.ROUND,
                            lineGradient = LineGradient(
                                interpolate {
                                    linear()
                                    lineProgress()
                                    stop {
                                        literal(0)
                                        rgba(47.0, 122.0, 198.0, 1.0)
                                    }
                                    stop {
                                        literal(1.0)
                                        rgba(47.0, 122.0, 198.0, 1.0)
                                    }
                                }
                            )
                        )
                    }
                }
            )

Maybe I am doing something wrong?

jush commented 3 months ago

@s23210 This seems to be an issue with mixing different versions of the multiple Mapbox SDKs. Could you please run the following command:

./gradlew app:dependencyInsight --configuration releaseRuntimeClasspath --dependency com.mapbox

replacing app with your app module and paste here the output related to mapbox versions.