maplibre / flutter-maplibre-gl

Customizable, performant and vendor-free vector and raster maps, flutter wrapper for maplibre-native and maplibre-gl-js (fork of flutter-mapbox-gl/maps)
https://pub.dev/packages/maplibre_gl
Other
226 stars 125 forks source link

[BUG] IllegalStateException: Calling getLayer when a newer style is loading/has loaded. #477

Open kai-trone opened 4 months ago

kai-trone commented 4 months ago

Platforms

android

Version of flutter maplibre_gl

0.20.0

Bug Description

We're using the maplibre widget in combination with AutomaticKeepAliveClientMixin so the map doesn't refresh when leaving the app. Showing thousands of markers and a searchbar to search for locations. We have our own tile server for the styleUrl. Our crashlytics overview was showing us a lot (at least 50%) of users are experiencing crashes, so I tried to re-create the error.

PS: This only happens on Android

Here's the crash output:

E/PlatformViewsController(11891): Disposing platform view threw an exception E/PlatformViewsController(11891): java.lang.IllegalStateException: Calling getLayer when a newer style is loading/has loaded. E/PlatformViewsController(11891): at org.maplibre.android.maps.Style.validateState(Style.java:776) E/PlatformViewsController(11891): at org.maplibre.android.maps.Style.getLayer(Style.java:239) E/PlatformViewsController(11891): at org.maplibre.android.location.SymbolLocationLayerRenderer.setLayerVisibility(SymbolLocationLayerRenderer.java:248) E/PlatformViewsController(11891): at org.maplibre.android.location.SymbolLocationLayerRenderer.hide(SymbolLocationLayerRenderer.java:110) E/PlatformViewsController(11891): at org.maplibre.android.location.LocationLayerController.hide(LocationLayerController.java:143) E/PlatformViewsController(11891): at org.maplibre.android.location.LocationComponent.disableLocationComponent(LocationComponent.java:1243) E/PlatformViewsController(11891): at org.maplibre.android.location.LocationComponent.setLocationComponentEnabled(LocationComponent.java:291) E/PlatformViewsController(11891): at org.maplibre.maplibregl.MapLibreMapController.destroyMapViewIfNecessary(MapLibreMapController.java:1778) E/PlatformViewsController(11891): at org.maplibre.maplibregl.MapLibreMapController.dispose(MapLibreMapController.java:1696) E/PlatformViewsController(11891): at io.flutter.plugin.platform.PlatformViewsController$1.dispose(PlatformViewsController.java:254) E/PlatformViewsController(11891): at io.flutter.plugin.platform.PlatformViewsController.diposeAllViews(PlatformViewsController.java:1072) E/PlatformViewsController(11891): at io.flutter.plugin.platform.PlatformViewsController.onPreEngineRestart(PlatformViewsController.java:947) E/PlatformViewsController(11891): at io.flutter.embedding.engine.FlutterEngine$1.onPreEngineRestart(FlutterEngine.java:124) E/PlatformViewsController(11891): at io.flutter.embedding.engine.FlutterJNI.onPreEngineRestart(FlutterJNI.java:1206) E/PlatformViewsController(11891): at android.os.MessageQueue.nativePollOnce(Native Method) E/PlatformViewsController(11891): at android.os.MessageQueue.next(MessageQueue.java:335) E/PlatformViewsController(11891): at android.os.Looper.loopOnce(Looper.java:162) E/PlatformViewsController(11891): at android.os.Looper.loop(Looper.java:294) E/PlatformViewsController(11891): at android.app.ActivityThread.main(ActivityThread.java:8177) E/PlatformViewsController(11891): at java.lang.reflect.Method.invoke(Native Method) E/PlatformViewsController(11891): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) E/PlatformViewsController(11891): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)

Steps to Reproduce

  1. Initialize the map and everything around it.
  2. Restart the app

Expected Results

A functional map without crash errors. A way to reload the layer/style, checking the newest one and using that.

Actual Results

The result is the error. Even though we haven't been experiencing an actual crash, Crashlytics is really trying to let us know something is wrong since 50% of the users are getting this error.

Code Sample

I've tried to initialise some important aspects in the onStyleLoadedCallback, but that didn't fix it yet.

  ml.MapLibreMap mapLibreMap() {
    return ml.MapLibreMap(
      trackCameraPosition: true,
      myLocationEnabled: true,
      compassEnabled: false,
      myLocationRenderMode: ml.MyLocationRenderMode.gps,
      minMaxZoomPreference: const ml.MinMaxZoomPreference(2, 20),
      attributionButtonPosition: ml.AttributionButtonPosition.bottomLeft,
      onUserLocationUpdated: (location) {
        if (MapEntity.locationUserPresent == false) {
          MapEntity.locationUserPresent = true;
        }
        MapEntity().updateUserLocation(LatLng(
          location.position.latitude,
          location.position.longitude,
        ));
      },
      onCameraIdle: onCameraIdle,
      tiltGesturesEnabled: false,
      onMapCreated: (controller) async {
        _mlMapController = controller;
        _mlMapController.addListener(onCameraMove);
        _mlMapController.onSymbolTapped.add(onSymbolTapped);
        initList();
      },
      onStyleLoadedCallback: () async {
        _styleLoadedCompleter.complete();

        await _mlMapController.loadImages();
        await _mlMapController.setSymbolIconAllowOverlap(true);
        await _mlMapController.setSymbolIconIgnorePlacement(true);

        _isStyleLoaded = true;

        loadMarkers();
      },
      initialCameraPosition: initialCameraPos,
      styleString: Camperstop.noPoiMapStyle,
    );
  }
imerzi commented 3 months ago

It happend to me when myLocationEnabled is set at true, and MyLocationTrackingMode is set to something else than None, could it be link to this ? And the updateUserLocation

kai-trone commented 3 months ago

Thanks for taking a look! Unfortunately MyLocationRenderMode doesn't have a None setting

(Copied from maplibre) /// Specifies if and how the user's heading/bearing is rendered in the user location indicator. enum MyLocationRenderMode { /// Do not show the user's heading/bearing. normal,

/// Show the user's heading/bearing as determined by the device's compass. On iOS, this causes the user's location to be shown on the map. compass,

/// Show the user's heading/bearing as determined by the device's GPS sensor. Not supported on iOS. gps, }

Are you maybe referring to something else?

Josh-Dovey commented 3 months ago

I get the same error on Android. This seems to be related to myLocationEnabled: true,.

When using myLocationEnabled: false, I don't get the error.

It does not appear to be related to myLocationRenderMode as the error appears using any of the MyLocationRenderMode options.

sqcsabbey commented 2 months ago

I'm getting this issue without myLocationEnabled: true, but I am dynamically updating the map position and zoom.

sqcsabbey commented 2 months ago

This looks related: https://stackoverflow.com/a/75843580/2199492