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
466 stars 131 forks source link

App crashes with java.lang.IllegalStateException when loading style #1511

Closed zhurbaTT closed 2 years ago

zhurbaTT commented 2 years ago

Environment

Observed behavior and steps to reproduce

In Firebase I see some crash events. It happens not very often. The trace is:

_Fatal Exception: java.lang.IllegalStateException com.mapbox.maps.UtilsKt.call (Utils.kt:9) com.mapbox.maps.MapboxMap.loadStyleUri (MapboxMap.kt:107) com.mapbox.maps.MapboxMap.loadStyle (MapboxMap.kt:168) com.mapbox.maps.MapboxMap.loadStyle (MapboxMap.kt:181) ru.trendagent.map.domain.mapService.modehelpers.SingleBlockModeHelper.initMap (SingleBlockModeHelper.kt:59) ru.trendagent.map.domain.mapService.MapBoxService.start (MapBoxService.kt:99) ru.trendagent.map.domain.usecase.LoadMapUseCase$loadSingleBlockMap$1.invoke (LoadMapUseCase.kt:53) ru.trendagent.map.domain.usecase.LoadMapUseCase$loadSingleBlockMap$1.invoke (LoadMapUseCase.kt:50) trendmultiplatform.api.terminal.Terminal$getMapDetail$2.invoke (Terminal.kt:1338) trendmultiplatform.api.terminal.Terminal$getMapDetail$2.invoke (Terminal.kt:1289) multiplatformrx.SingleReq$multiRequests$1$2.invokeSuspend (SingleReq.kt:108) kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33) kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:106) android.os.Handler.handleCallback (Handler.java:938) com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1135)

Notes / preliminary analysis

Looks like nativeMap weak reference is not existing anymore. How can this happen? The problem affects only a part of our users.

ZiZasaurus commented 2 years ago

@zhurbaTT when is this crash happening? Can you provide a code snippet or a sample application that reproduces this behavior so we can see what could be causing it?

zhurbaTT commented 2 years ago

Hello @ZiZasaurus , unfortunately I can't send a code snippet, cause it is under NDA. But I can describe what we are doing.

We have a fragment, viewModel and the mapService, that incapsulates all work with mapBox. In fragment's onCreateView() we give a mapBox reference (binding.mapView.getMapboxMap()) to the viewModel (and it gives this reference to the mapService). Inside fragment's onStart() we are forcing mapService to initialize the map and it loads the style like so:

style(styleUri = Style.MAPBOX_STREETS) {
                +image(SELECTED_MARKER_IMAGE_ID) {
                    bitmap(resHelper.drawables[ICON_SELECTED_MARKER]!!.toBitmap())
                }
                +image(UNSELECTED_MARKER_IMAGE_ID) {
                    bitmap(resHelper.drawables[ICON_UNSELECTED_MARKER]!!.toBitmap())
                }
                +geoJsonSource(id = BLOCK_MARKERS_SRC_ID) {
                    featureCollection(resHelper.blocksFeatures!!)
                    cluster(true)
                    clusterMaxZoom(12)
                    clusterRadius(50)
                }
                +circleLayer(layerId = CLUSTER_BLOCK_LAYER_ID, sourceId = BLOCK_MARKERS_SRC_ID) {
                    circleColor(resHelper.colors[CIRCLE_LAYER_CIRCLE_COLOR]!!)
                    circleRadius(18.0)
                    circleStrokeWidth(2.0)
                    circleStrokeColor(resHelper.colors[CIRCLE_LAYER_STROKE_COLOR]!!)
                    filter(Expression.has(POINT_COUNT_PROPERTY))
                }
                +symbolLayer(layerId = COUNT_LAYER_ID, sourceId = BLOCK_MARKERS_SRC_ID) {
                    textField("{$POINT_COUNT_PROPERTY}")
                    textSize(12.0)
                    textColor(resHelper.colors[COUNT_LAYER_TEXT_COLOR]!!)
                }
                +symbolLayer(layerId = BLOCK_MARKERS_LAYER_ID, sourceId = BLOCK_MARKERS_SRC_ID) {
                    iconImage(
                        switchCase {
                            eq {
                                get {
                                    literal(SELECTED_PROPERTY)
                                }
                                literal(true.toString())
                            }
                            literal(SELECTED_MARKER_IMAGE_ID)
                            literal(UNSELECTED_MARKER_IMAGE_ID)
                        }
                    )
                    iconAllowOverlap(true)
                    iconAnchor(IconAnchor.BOTTOM)
                    filter(Expression.not(Expression.has(POINT_COUNT_PROPERTY)))
                }
            }
        ) { style ->
            style.localizeLabels(Locale(LOCALE_RU, LOCALE_RU.uppercase()))
        }
kiryldz commented 2 years ago

@zhurbaTT 10.3.0 is pretty outdated version, weak references for map / style were revisited in v10.5.0.

In general when reloading the style - you should update all local references to Style in your codebase (same applies if you're storing MapboxMap object). In v10.5.0 and after crashes you described should not happen but you will see warning log messages that you're potentially leaking map / style.

zhurbaTT commented 2 years ago

Thank you, @kiryldz ! We will set the mapBox dependency version to the latest one and check how it will affect our users. I'll come back with new info in 1 week.

zhurbaTT commented 2 years ago

I don't see any new cases after upgrading to 10.6.2.