mapbox-maps-android icon indicating copy to clipboard operation
mapbox-maps-android copied to clipboard

java.lang.Error: wstring_convert: to_bytes error

Open NelsonBeard opened this issue 1 year ago • 7 comments

Environment

  • Android OS version: 13
  • Devices affected: Poco F3 (MIUI 12,5)
  • Maps SDK Version: 9.5.0

Observed behavior and steps to reproduce

Application crashes with next stacktrace: java.lang.Error: wstring_convert: to_bytes error at com.mapbox.mapboxsdk.maps.renderer.MapRendererRunnable.run(MapRendererRunnable.java) at com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.MapboxGLSurfaceView$GLThread.guardedRun(MapboxGLSurfaceView.java:758) at com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.MapboxGLSurfaceView$GLThread.run(MapboxGLSurfaceView.java:568)

Expected behavior

No application crash

Notes / preliminary analysis

Hi! Many users of our app got this crash. I can't reproduce it by my own. App crashes whenever it wants - on startup, on map clicks, after block/unblock screen, etc. All this information (and stacktrace) i get via Sentry (issue monitoring tool)

Can you help me with this crash, please?

P.S. Maybe update Maps SDK Version to newest can solve this problem?

Additional links and references

Most similar issue was https://github.com/mapbox/mapbox-maps-android/issues/1054#issuecomment-1014568705, but i don't see solution there

NelsonBeard avatar Jul 03 '23 13:07 NelsonBeard

Following #1054, I also just discovered this crash

Pixel 6 Pro, Android 13 Mapbox SDK 10.12.2

My code that can get called multiples times looks something like:

map.getStyle()?.setStyleGeoJSONSourceData(sourceIdentifier, GeoJSONSourceData(feature))

val lastLayerInfo = map.getStyle()?.styleLayers?.lastOrNull()
val layer = map.getStyle()?.getLayer(circleLayerIdentifier)
if (
    layer != null &&
    lastLayerInfo != null &&
    layer.layerId != lastLayerInfo.id
) {
    map.getStyle()?.moveStyleLayer(circleLayerIdentifier, null)
}

I can load the map just fine on the first app load, rendering features, annotations, and whatnot. I noticed when switching to and from the mapview screen few times, or even staying on the mapview screen and toggling state values (causing the screen to rerender), the app will crash. circleLayerIdentifier in my case is in the format alpha:alphanumeric

Commenting out the if block above, I can't get my app to crash (but my layer is not where it should be obviously).

okcoker avatar Jul 03 '23 23:07 okcoker

Still trying to figure this out, but I thought I should also probably mention I'm using jetpack compose, and my MapView is wrapped with an AndroidView. Not sure if OP is as well.

okcoker avatar Jul 16 '23 17:07 okcoker

I'm starting to feel like this is on the mapbox native side rather than it being my code. I cannot run this project locally for the life of me in order to further debug due to errors with kaptGenerateStubsPublicDebugKotlin and cannot access class com.sun.tools.javac.util.Context (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.util to unnamed module.

In the meantime this comment gave me the idea to ignore moveStyleLayer entirely for now in favor of removing my layer and re-adding it. It's definitely not as ideal or ergonomic but my app seems to load now which is progress.

okcoker avatar Jul 19 '23 05:07 okcoker

Ok so I managed to get the app building and running. I have a simple way to reproduce this error.

In the compose-app module, replace your MapboxMap() function with the code below and you will see the app crash after the first tick update. Full file with imports

private fun MapboxMap() {
  val mapView = mapView()
  val mapIsReady = remember { mutableStateOf(false) }
  var ticker by remember { mutableStateOf(0) }

  fun ensureCircleSource(circleId: String, mapView: MapView) {
    val map = mapView.getMapboxMap()
    val sourceIdentifier = "source:${circleId}"
    val source = map.getStyle()?.getSourceAs(sourceIdentifier) ?: GeoJsonSource.Builder(sourceIdentifier).build()

    if (map.getStyle()?.styleSourceExists(sourceIdentifier) != true) {
      source.data("")
      map.getStyle()?.addSource(source)
    }
  }

  fun drawCircle(mapView: MapView, id: String) {
    val map = mapView.getMapboxMap()
    val circleId = id
    ensureCircleSource(circleId, mapView)

    val sourceIdentifier = "source:${circleId}"
    val circleLayerIdentifier = "layer:${circleId}"
    val feature = Feature.fromGeometry(Point.fromLngLat(LONGITUDE, LATITUDE), null, "feature:${circleId}")

    // Source should already be appended at this point, so update the geojson now
    map.getStyle()?.setStyleGeoJSONSourceData(sourceIdentifier, GeoJSONSourceData(feature))

    val lastLayerInfo = map.getStyle()?.styleLayers?.lastOrNull()

    if (map.getStyle()?.styleLayerExists(circleLayerIdentifier) != true) {
      val color = if (id == "circle1") "rgb(255, 0, 0)" else "rgb(0, 255, 0)"
      val circleLayer = CircleLayer(circleLayerIdentifier, sourceIdentifier)
      circleLayer.circleColor(color)
      circleLayer.circleRadius(16.0)

      map.getStyle()?.addLayer(circleLayer)
    }
    else {
      val style = map.getStyle()!!
      val layer = style.getLayer(circleLayerIdentifier)

      if (
        layer != null &&
        lastLayerInfo != null &&
        layer.layerId != lastLayerInfo.id
      ) {
        // Move to top
        if (style.styleLayerExists(layer.layerId)) {
          style.moveStyleLayer(layer.layerId, null)
        }
      }
    }
  }

  // Simulate view updates every second
  LaunchedEffect(ticker) {
    while (true) {
      delay(4000)
      ticker = 1 - ticker
    }
  }

  AndroidView(
    factory = {
      val mapboxMap = mapView.getMapboxMap()
      mapboxMap
        .apply {
          loadStyleUri(Style.MAPBOX_STREETS)
          setCamera(
            CameraOptions.Builder()
              .center(Point.fromLngLat(LONGITUDE, LATITUDE))
              .zoom(9.0)
              .build()
          )
        }
      var observer: Observer? = null

      observer = Observer {
        observer?.let {
          mapboxMap.unsubscribeMapLoaded(it)
        }
        mapIsReady.value = true
      }

      mapboxMap.subscribeMapLoaded(observer)

      mapView
    },
    modifier = Modifier.fillMaxSize()
  ) update@{ mapView ->
    if (!mapIsReady.value) {
      return@update
    }

    Log.d("Ticker", "update $ticker")
    drawCircle(mapView, "circle1")
    drawCircle(mapView, "circle2")
  }
}

okcoker avatar Jul 31 '23 05:07 okcoker

Hey @NelsonBeard Maps SDK v9 is out dated and won't receive new fixes and please update to latest v10 stable releases for more bug fixes/improvements.

Hey @okcoker have you tried our compose extension and see if you experience similar issues ?

pengdev avatar Nov 06 '23 13:11 pengdev

Hey @okcoker have you tried our compose extension and see if you experience similar issues ?

I have not, but will take a look and report back. Looking briefly at your link, it looks like I'll have to upgrade from v10 to v11 to try this out. Were you able to reproduce my issue above and fix it with the compose extension?

okcoker avatar Nov 06 '23 18:11 okcoker

I have not, but will take a look and report back. Looking briefly at your link, it looks like I'll have to upgrade from v10 to v11 to try this out.

Thanks!

Were you able to reproduce my issue above and fix it with the compose extension?

No I haven't, will git it a try

pengdev avatar Nov 08 '23 15:11 pengdev