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
478 stars 134 forks source link

Changing Map style in runtime [CRASH] #2386

Closed Plovotok closed 4 months ago

Plovotok commented 6 months ago

Environment

Problem

Crash when chnging map style in runtime, 11.4.0 bug not fixed
Application crashes when I try to change map in runtime style with strace:
pid: 7268, tid: 7337, name: MapboxRenderThr  >>> com.example.maps <<<
#00 pc 000000000051e9db  /data/app/~~wiKGLnaLDsbumACY3UW8cA==/com.example.maps-XNFb5_KxO-1Rqdvh6YZKXQ==/base.apk!libmapbox-maps.so (BuildId: 74cdcfc4da0fad832bb5b2162fc376a60789f77e)
#01 pc 000000000051e9db  /data/app/~~wiKGLnaLDsbumACY3UW8cA==/com.example.maps-XNFb5_KxO-1Rqdvh6YZKXQ==/base.apk!libmapbox-maps.so (BuildId: 74cdcfc4da0fad832bb5b2162fc376a60789f77e)
#02 pc 000000000051e9db  /data/app/~~wiKGLnaLDsbumACY3UW8cA==/com.example.maps-XNFb5_KxO-1Rqdvh6YZKXQ==/base.apk!libmapbox-maps.so (BuildId: 74cdcfc4da0fad832bb5b2162fc376a60789f77e)
...
#18 pc 00000000001b2e78  /data/app/~~wiKGLnaLDsbumACY3UW8cA==/com.exampe.maps-XNFb5_KxO-1Rqdvh6YZKXQ==/base.apk (com.mapbox.maps.NativeMapImpl.render+4)
#20 pc 000000000036cc60  /data/app/~~wiKGLnaLDsbumACY3UW8cA==/com.example.maps-XNFb5_KxO-1Rqdvh6YZKXQ==/base.apk (com.mapbox.maps.renderer.MapboxRenderer.render+8)
#22 pc 000000000036b6c6  /data/app/~~wiKGLnaLDsbumACY3UW8cA==/com.example.maps-XNFb5_KxO-1Rqdvh6YZKXQ==/base.apk (com.mapbox.maps.renderer.MapboxRenderThread.draw+198)
#24 pc 000000000036b520  /data/app/~~wiKGLnaLDsbumACY3UW8cA==/com.example.maps-XNFb5_KxO-1Rqdvh6YZKXQ==/base.apk (com.mapbox.maps.renderer.MapboxRenderThread.doFrame+256)

Code

@Composable
fun MapContent(
    mapViewportState: MapViewportState,
    currentMapStyle: String,
    onMapClickListener: OnMapClickListener,
    onMapLongClickListener: OnMapLongClickListener,
    content: (@Composable @MapboxMapComposable MapboxMapScope.() -> Unit)? = null
) {
    val locationComponentSettings =
        DefaultSettingsProvider.defaultLocationComponentSettings(
            LocalDensity.current.density
        ).toBuilder().apply {
            enabled = true
            puckBearingEnabled = true
            showAccuracyRing = true
            locationPuck = createDefault2DPuck(true)
        }.build()
    MapboxMap(
        Modifier.fillMaxSize(),
        composeMapInitOptions = ComposeMapInitOptions(
            LocalDensity.current.density,
            textureView = true
        ),
        locationComponentSettings = locationComponentSettings,
        style = {
                GenericStyle(style = currentMapStyle)
        },
        onMapClickListener = onMapClickListener,
        onMapLongClickListener = onMapLongClickListener,
        mapViewportState = mapViewportState
    ) {
        content?.let { it() }
    }
}
Plovotok commented 6 months ago

Changing style only after onStyleLoaded or onMapLoaded callback also crashes the app

Plovotok commented 5 months ago

https://github.com/mapbox/mapbox-maps-android/assets/59875059/ffc68708-2b63-4464-917e-d1107db178b3

kiryldz commented 5 months ago

@Plovotok thanks, we will take a look if we could reproduce this one.

Plovotok commented 5 months ago

App usually crashes after some action with camera like MapViewportState#flyTo or MapViewportState#easeTo. If camera state changes cause of user interaction, application works normally

natiginfo commented 5 months ago

@Plovotok we tried to reproduce the issue, but we weren't successful. Could you please try v11.5.0-beta.1? If the issue persists, we would appreciate if you could provide minimum working example to us.

Plovotok commented 5 months ago

seems like problem reproducable if I change maps style and call

MapEffect(showTraffic) {
            it.location.apply {
                enabled = true
                puckBearingEnabled = true
                showAccuracyRing = true
                locationPuck = createDefault2DPuck(true)
            }

            it.mapboxMap.style?.setStyleLayerProperty(
                "traffic",
                "visibility",
                Value.valueOf(if (showTraffic) "visible" else "none")
            )
        }

I have own style with traffic layer and change it by toggling button. If I don't call setStyleLayerProperty, everything works fine

natiginfo commented 4 months ago

@Plovotok I tried following sample which sets style layer property but did not observe any crash. If you could provide an example project where this issue is reproducible, we could investigate the issue further. Here is the code where I tried to reproduce the issue (Following example updates changes style and sets visibility of layer that is common for given styles):

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import com.mapbox.common.MapboxOptions
import com.mapbox.geojson.Point
import com.mapbox.maps.MapboxExperimental
import com.mapbox.maps.Style
import com.mapbox.maps.coroutine.awaitStyle
import com.mapbox.maps.extension.compose.MapEffect
import com.mapbox.maps.extension.compose.MapboxMap
import com.mapbox.maps.extension.compose.animation.viewport.rememberMapViewportState
import com.mapbox.maps.extension.compose.style.MapStyle
import com.mapbox.maps.extension.compose.style.layers.generated.Visibility
import com.mapbox.maps.plugin.locationcomponent.createDefault2DPuck
import com.mapbox.maps.plugin.locationcomponent.location

@OptIn(MapboxExperimental::class)
class MainActivity : ComponentActivity() {
    private val styles = arrayOf(
        Style.STANDARD,
        Style.LIGHT,
        Style.DARK,
        Style.MAPBOX_STREETS,
        Style.TRAFFIC_DAY,
        Style.TRAFFIC_NIGHT,
        Style.OUTDOORS,
        Style.SATELLITE_STREETS,
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        MapboxOptions.accessToken = Constants.MAPBOX_ACCESS_TOKEN
        setContent {
            var showStyleLayer by remember { mutableStateOf(false) }
            var styleIndex by remember { mutableStateOf(0) }
            Scaffold(
                floatingActionButton = {
                    FloatingActionButton(onClick = {
                        showStyleLayer = !showStyleLayer
                        styleIndex += 1
                    }) {
                        Icon(Icons.Filled.Refresh, "Change style")
                    }
                }
            ) { padding ->
                MapboxMap(
                    Modifier
                        .fillMaxSize()
                        .padding(padding),
                    mapViewportState = rememberMapViewportState {
                        setCameraOptions {
                            zoom(9.0)
                            center(Point.fromLngLat(24.941526986277893, 60.17099952463323))
                        }
                    },
                    style = {
                        MapStyle(style = styles[styleIndex % styles.size])
                    }
                ) {
                    MapEffect(showStyleLayer) {
                        it.location.apply {
                            enabled = true
                            puckBearingEnabled = true
                            showAccuracyRing = true
                            locationPuck = createDefault2DPuck(true)
                        }
                        val style = it.mapboxMap.awaitStyle()
                        val visibility =
                            if (showStyleLayer) Visibility.VISIBLE.value else Visibility.NONE.value
                        style.setStyleLayerProperty(
                            "mapbox-location-indicator-layer",
                            "visibility",
                            visibility
                        )
                    }
                }
            }
        }
    }
}
CCCCauchy commented 4 months ago

@jush I've been consistently encountering the same crash logs on Google Play, but the issue has never been reproducible until recently when a user reported it to us and even provided a screen recording of the problem. Whenever this user opens a page that uses the Mapbox map, the app crashes. However, after restarting the phone, the issue no longer occurs.

  1. My app does not use NDK compilation.
  2. Due to the use of libc++_shared in another AAR file, we added a series of configurations such as pickFirst '**/**/libc++_shared.so' in our packagingOptions. I'm unsure if this has any impact.
  3. Mapbox map version is 11.4.0.
kiryldz commented 4 months ago

@CCCCauchy this explains the crashes. All the libraries with native code must be aligned. Mapbox Maps v11 is built with NDK 23. We do not support multiple NDK builds (as of now) so the solution will be try to align another library that's also built with NDK (most likely it's NDK 21 or lower).

CCCCauchy commented 4 months ago

@CCCCauchy this explains the crashes. All the libraries with native code must be aligned. Mapbox Maps v11 is built with NDK 23. We do not support multiple NDK builds (as of now) so the solution will be try to align another library that's also built with NDK (most likely it's NDK 21 or lower).

@kiryldz May i can downgrade mapbox below v11 to solve this issue?

kiryldz commented 4 months ago

@CCCCauchy firstly you have to understand what NDK is used for your another 3d party library with C++. If you will confirm it's NDK 21 - our Maps v10 are built with NDK 21 so downgrade will help in that case.

CCCCauchy commented 4 months ago

@CCCCauchy firstly you have to understand what NDK is used for your another 3d party library with C++. If you will confirm it's NDK 21 - our Maps v10 are built with NDK 21 so downgrade will help in that case.

After investigating, we found that most of the third-party libraries in our app use NDK lower than 23. Last week, we downgraded Mapbox to V10, and this issue has significantly decreased on Google Play. Thank you for your help.