MapboxMap.style.getSource(id) returns null
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
@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?
Push, please provide any hint or comment. It's been over a month now.
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.
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"))
],
),
),
);
}
}
@yunikkk Could you reproduce the issue?
@kamami checked, I can indeed reproduce, will take a deeper look, thanks.
@kamami checked it again, there might be couple unrelated things going on here :
datafor 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
onStyleLoadedcallback.
What I suggest is to check that your source is working adding some layer after style is loaded.
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 'GeoJsonSource.data' always returns null, this is done for optimization reasons
@evil159 how can i get this data ?
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