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

Android: setStyleJSON not working after upgrading plugin version 2+

Open felixkrautschuk opened this issue 1 year ago • 7 comments

After upgrading the plugin from version 1.1.0 to 2.0.0, I have some issues when developing for Android.

I try to set a custom style json like this in the onMapCreated callback:


_onMapCreated(MapboxMap mapboxMap) async {
    this.mapboxMap = mapboxMap;

    final styleJson = await rootBundle.loadString("assets/map-styles/my_style.json");
    mapboxMap.style.setStyleJSON(styleJson);

    print("done");
}

I see the log message in the console, so the code is executed as expected without any error, but I still see the default Mapbox style on Android. It is working as expected on iOS and it was also working on Android using plugin version 1.1.0.

Futhermore, when adding a layer in the onStyleLoadedListener like this:

_onMapStyleLoaded(StyleLoadedEventData styleLoadedEventData) async {
    final linesData = await rootBundle.loadString('assets/map-data/lines.json');
    await mapboxMap?.style.addSource(GeoJsonSource(id: "source_lines", data: linesData));
    await mapboxMap?.style.addLayer(
        LineLayer(
            id: "layer_lines",
            sourceId: "source_lines"
        )
    );
}

I see the added layer, but I also see an exception on Android:

E/flutter (22160): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(Throwable, java.lang.Throwable: Source source_lines already exists, Cause: null, Stacktrace: java.lang.Throwable: Source source_lines already exists E/flutter (22160): at com.mapbox.maps.mapbox_maps.StyleController.addStyleSource(StyleController.kt:288) E/flutter (22160): at com.mapbox.maps.mapbox_maps.pigeons.StyleManager$Companion.setUp$lambda-51$lambda-50(MapInterfaces.kt:5972) E/flutter (22160): at com.mapbox.maps.mapbox_maps.pigeons.StyleManager$Companion.$r8$lambda$DXAQ35E-7m0eWhGSNgtBkwfDJqQ(Unknown Source:0) E/flutter (22160): at com.mapbox.maps.mapbox_maps.pigeons.StyleManager$Companion$$ExternalSyntheticLambda8.onMessage(Unknown Source:2) E/flutter (22160): at io.flutter.plugin.common.BasicMessageChannel$IncomingMessageHandler.onMessage(BasicMessageChannel.java:261) E/flutter (22160): at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:292) E/flutter (22160): at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:319) E/flutter (22160): at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12) E/flutter (22160): at android.os.Handler.handleCallback(Handler.java:958) E/flutter (22160): at android.os.Handler.dispatchMessage(Handler.java:99) E/flutter (22160): at android.os.Looper.loopOnce(Looper.java:205) E/flutter (22160): at android.os.Looper.loop(Looper.java:294) E/flutter (22160): at android.app.ActivityThread.main(ActivityThread.java:8177) E/flutter (22160): at java.lang.reflect.Method.invoke(Native Method) E/flutter (22160): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) E/flutter (22160): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) E/flutter (22160): , null) E/flutter (22160): #0 StyleManager.addStyleSource (package:mapbox_maps_flutter/src/pigeons/map_interfaces.dart:5816:7) E/flutter (22160): E/flutter (22160): #1 StyleSource.addSource. (package:mapbox_maps_flutter/src/style/style.dart:317:66) E/flutter (22160): E/flutter (22160): #2 MapPageState._onMapStyleLoaded (package:flutter_mapbox/main.dart:48:5) E/flutter (22160):

It is working as expected on iOS and it was also working on Android with plugin 1.1.0.

Full sample project: flutter_mapbox.zip

felixkrautschuk avatar Jun 28 '24 13:06 felixkrautschuk

I just noticed that the same PlatformException also occurs on iOS:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(0, Source source_lines already exists, null, null) #0 StyleManager.addStyleSource (package:mapbox_maps_flutter/src/pigeons/map_interfaces.dart:5816:7) #1 StyleSource.addSource. (package:mapbox_maps_flutter/src/style/style.dart:317:66) #2 MapPageState._onMapStyleLoaded (package:flutter_mapbox/pages/map-page.dart:54:5)

felixkrautschuk avatar Jul 18 '24 15:07 felixkrautschuk

on iOS, the issue does not occur when setting styleUri to an empty string

MapWidget(
          //...
          styleUri: "",
          //...
),

but that does not help on Android

felixkrautschuk avatar Jul 18 '24 15:07 felixkrautschuk

Hey! Any news on this topic? I get the same exact issue when trying to load polyline on Android (no issue on iOS) @felixkrautschuk were you able to find a workaround?

mabilinab avatar Sep 30 '24 19:09 mabilinab

@mabilinab adding a delay works for me on Android

_onMapCreated(MapboxMap mapboxMap) async {
    final styleJson = await rootBundle.loadString("assets/map-styles/my_style.json");

    Future.delayed(const Duration(milliseconds: 50), () {
      mapboxMap.style.setStyleJSON(styleJson);
    });
 }

However, I don't like this as there is no guarantee that 50ms is always enough.

felixkrautschuk avatar Oct 08 '24 14:10 felixkrautschuk

I was also able to find a workaround: It seems like when you import a custom map URL, you need to use await -- this solved most of the issues for me:

void _onMapCreated(MapboxMap mapboxMap) async {
    _mapboxMap = mapboxMap;
    //Initialize the map settings
    await _mapboxMap!.loadStyleURI("mapbox://styles/XXX/XXXXXX");
  }

  _onStyleLoadedCallback(StyleLoadedEventData data) async {
//.... rest of your code

mabilinab avatar Oct 16 '24 17:10 mabilinab

how complicated to add a style layer adding feature? Always producing bugs.

themumy10 avatar Nov 16 '24 19:11 themumy10

Is there any update on this issue? Using mapbox_maps_flutter 2.6.0 on iOS 18.3, the map style loads inconsistently with no errors in the debug console.

MapWidget(
              key: const ValueKey("mapWidget"),
              onMapCreated: _onMapCreated,
              onStyleLoadedListener: _onStyleLoaded),
  _onMapCreated(MapboxMap mapboxMap) async {
    this.mapboxMap = mapboxMap;
  }
  _onStyleLoaded(StyleLoadedEventData data) async {
    addModalLayer();
  }

  addModalLayer() async {
    if (mapboxMap == null) {
      throw Exception("MapboxMap is not ready yet");
    }

    final map = mapboxMap!;

    // Add GeoJSON sources

    await map.style.addSource(GeoJsonSource(
      id: "flag-source",
      data: jsonEncode(Point(coordinates: Position(endLon, endLat))),
    ));

    // Add model layer for flag
    var flagLayer = ModelLayer(
      id: "flag-layer",
      sourceId: "flag-source",
    );
    flagLayer.modelId = "asset://assets/models/location-pin.glb";
    flagLayer.modelScale = [100.0, 100.0, 100.0];
    flagLayer.modelRotation = [0, 0, 0];
    flagLayer.modelType = ModelType.LOCATION_INDICATOR;
    await map.style.addLayer(flagLayer);

    // Drwaing geojson line
    await map.style
        .addSource(GeoJsonSource(id: "line", data: jsonEncode(mapData)));
    await map.style.addLayer(LineLayer(
      id: "line_layer",
      sourceId: "line",
      lineJoin: LineJoin.ROUND,
      lineCap: LineCap.ROUND,
      lineColor: FlutterFlowTheme.of(context).primary.value,
      lineWidth: 6.0,
    ));

    map.flyTo(
      CameraOptions(
        center: Point(coordinates: Position(startLon, startLat)),
        zoom: 15,
        bearing: 60,
        pitch: 60,
      ),
      MapAnimationOptions(duration: 1000, startDelay: 0),
    );
  }

WaseekSenju avatar May 06 '25 07:05 WaseekSenju