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

MapboxMap.style.getSource(id) returns null

Open kamami opened this issue 2 years ago • 12 comments

Why is this printing null to the console?

  await mapboxMap?.style.addStyleSource(
          "chargers",
          json.encode({
            "type": "geojson",
            "data": {
              "type": "FeatureCollection",
              "features": [
                {
                  "id": "39169",
                  "type": "Feature",
                  "properties": {
                    "fastCharger": false,
                    "powerKW": "22 KW",
                    "name": "Rathaus Altona"
                  },
                  "geometry": {
                    "type": "Point",
                    "coordinates": [9.93550387483399, 53.5464387674623]
                  }
                },
              ]
            },
            "cluster": true,
            "clusterMaxZoom": 14,
            "clusterRadius": 50
          }));

      final GeoJsonSource source =
          await mapboxMap.?.style.getSource("chargers") as GeoJsonSource;

      print(await source.data); ==> null

kamami avatar Jan 19 '23 16:01 kamami

@yunikkk Sorry to mention you here, but I think this deserves some attention. I can not explain why this is not working and I am stuck on this for weeks now. Did I do anything wrong on my side?

kamami avatar Feb 09 '23 12:02 kamami

Push, please provide any hint or comment. It's been over a month now.

kamami avatar Feb 22 '23 10:02 kamami

Hey @kamami, thanks for the report and sorry for a long reply, was pretty busy with different issues and on a vacation last few weeks. I suspect you might need to wait for the geojson data to be loaded, easiest way to check it's the case is to add some delay (a second for example) and check data then. The more correct approach would be to wait for the SOURCE_DATA_LOADED map event adding listener e.g. demonstrated here : https://github.com/mapbox/mapbox-maps-flutter/blob/main/example/lib/full_map.dart#L144.

yunikkk avatar Feb 22 '23 12:02 yunikkk

Hey @yunikkk, I hope you had a nice vacation!

Adding a delay did not help. Clicking the button whenever I want just prints null;

Here is btw my minimum reproduction example:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart';

void main() async {
  runApp(Test());
}

class Test extends StatelessWidget {
  Test({Key? key}) : super(key: key);

  MapboxMap? mapController;

  _onMapCreated(MapboxMap controller) async {
    mapController = controller;

    await controller.style.addStyleSource(
        "chargers",
        json.encode({
          "type": "geojson",
          "data": {
            "type": "FeatureCollection",
            "features": [
              {
                "id": "39169",
                "type": "Feature",
                "properties": {
                  "fastCharger": false,
                  "powerKW": "22 KW",
                  "name": "Rathaus Altona"
                },
                "geometry": {
                  "type": "Point",
                  "coordinates": [9.93550387483399, 53.5464387674623]
                }
              },
            ]
          },
          "cluster": true,
          "clusterMaxZoom": 14,
          "clusterRadius": 50
        }));
  }

  buttonClicked() async {
    final GeoJsonSource source =
        await mapController?.style.getSource("chargers") as GeoJsonSource;

    print(await source.data);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            SizedBox(
              height: 400,
              width: 400,
              child: MapWidget(
                resourceOptions: ResourceOptions(
                    accessToken: "XXX"),
                onMapCreated: _onMapCreated,
              ),
            ),
            TextButton(onPressed: buttonClicked, child: const Text("Get Source"))
          ],
        ),
      ),
    );
  }
}

kamami avatar Feb 24 '23 14:02 kamami

@yunikkk Could you reproduce the issue?

kamami avatar Mar 01 '23 09:03 kamami

@kamami checked, I can indeed reproduce, will take a deeper look, thanks.

yunikkk avatar Mar 02 '23 18:03 yunikkk

@kamami checked it again, there might be couple unrelated things going on here :

  • data for with inline geojson is expected to be empty, see android docs, the comment in dart does not mention that however. At the same time data is still there and a layer added to the source should work fine.
  • due to the recently added bug in Android implementation geojson added before style loaded is not added correctly, it will work only when added after the style loading, e.g. in onStyleLoaded callback.

What I suggest is to check that your source is working adding some layer after style is loaded.

yunikkk avatar Mar 03 '23 15:03 yunikkk

Is there any chance this is going to be fixed? I am using plugin version 1.1.0 and source.data still returns null, even when adding the source after the style is loaded.

felixkrautschuk avatar Apr 26 '24 09:04 felixkrautschuk

@felixkrautschuk 'GeoJsonSource.data' always returns null, this is done for optimization reasons

evil159 avatar Apr 26 '24 13:04 evil159

@evil159 how can i get this data ?

lantah-1 avatar Aug 20 '24 06:08 lantah-1

also having this issue, without being able to get the data from a Source type class it prevents me from being able to update the GeoJson effectively, if I want to do this instead of passing a type safe class I have to pass the parameters and create the class in the place where I try to update the GeoJson.

eg. this won't work

Future<void> _addSources({
    required MapboxMap mapboxMap,
    required List<Source> sources,
  }) async {
    for (final source in sources) {
      try {
        // throws if source not found, so we catch and add source.
        final existingSource = await mapboxMap.style.getSource(source.id);

        if (existingSource is! GeoJsonSource) {
          continue; // guard clause
        }

        final geoJsonSource = source as GeoJsonSource;
        final geoJsonSourceData = await geoJsonSource.data;

        if (geoJsonSourceData == null) {
          continue; // guard clause
        }

        await existingSource.updateGeoJSON(geoJsonSourceData);
      } catch (e) {
        await mapboxMap.style.addSource(source);
      }
    }
  }

as the data is null, instead I need to pass through the data to here and lose typing outside of this function. Alternative I see is I need to make a class with a type enum, this type enum on a switch statement will replicate how you do the get source switch on Source in style.dart -> getSource

Tristan-Rogers-Genvis avatar Oct 02 '24 07:10 Tristan-Rogers-Genvis