Basically i am getting a list of data for markers from a json file, i dont want to use setState
instead i am using a provider. everything works fine without error but my markers are not getting update in the flutter_map
here is the main class
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
MapController? osmController;
Future<void> startParam() async {
osmController = MapController();
MarkerListProvider markerListProvider = MarkerListProvider();
await markerListProvider.loadMarkers();
//await AirportMarkers.loadMarkers(context);
}
@override
void initState() {
super.initState();
startParam();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 950,
child: FlutterMap(
mapController: osmController!,
options: MapOptions(
center: LatLng(27.7000, 85.3333),
zoom: 8,
minZoom: 3,
// adaptiveBoundaries: true,
interactiveFlags: //InteractiveFlag.none
InteractiveFlag.pinchZoom | InteractiveFlag.drag,
),
children: [
TileLayer(
tileProvider: CachedTileProvider(),
urlTemplate:
// 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'),
Consumer<MarkerListProvider>(
builder: (BuildContext context, value, Widget? child) {
return MarkerLayer(markers: value.airportMarkers);
// );
}),
],
),
),
],
),
),
);
}
and this is the provider class
class MarkerListProvider extends ChangeNotifier {
List<Marker> airportMarkers = [];
Future<void> loadMarkers() async {
double markerWidth = 20;
double markerHeight = 20;
// Load the JSON file containing the markers
final String jsonString =
await rootBundle.loadString('assets/airport_markers.json');
// Decode the JSON data into a List of Maps
final List<dynamic> jsonData = await json.decode(jsonString);
// Create a List of Markers from the JSON data
List<Marker> apMarker = jsonData.map((data) {
final double latitude = data['point']['latitude'];
final double longitude = data['point']['longitude'];
final String text = data['text'];
return Marker(
width: markerWidth,
height: markerHeight,
point: LatLng(latitude, longitude),
builder: (ctx) => MarkerTap(str: text),
);
}).toList();
// Set the airportMarkers list and return it
airportMarkers = apMarker;
notifyListeners();
}
}
I know there is no problem with parsing and all because when i use it without provider in the main class with setState
all the markers populate just fine.
Future<void> loadMarkers() async {
double markerWidth = 20;
double markerHeight = 20;
// Load the JSON file containing the markers
final String jsonString =
await rootBundle.loadString('assets/airport_markers.json');
// Decode the JSON data into a List of Maps
final List<dynamic> jsonData = json.decode(jsonString);
// Create a List of Markers from the JSON data
// List<Marker> apMarker = [];
apMarker = jsonData.map((data) {
final double latitude = data['point']['latitude'];
final double longitude = data['point']['longitude'];
final String text = data['text'];
return Marker(
width: markerWidth,
height: markerHeight,
point: LatLng(latitude, longitude),
builder: (ctx) => MarkerTap(str: text),
);
}).toList();
setState(() {
});
}
what seems to be the problem here ? my data is big contains world airports.
You have to register the provider on your app and then fetch the data from the context.
On the main:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Preferences.init();
runApp(const AppState());
}
class AppState extends StatelessWidget {
const AppState({super.key});
@override
Widget build(BuildContext context) {
return MultiProvider(providers: [
ChangeNotifierProvider(create: (_) => MarkerListProvider(),
lazy:true)], child: const MyApp());
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
initialRoute: AppRoutes.initialRoute(),
routes: AppRoutes.getAppRoutes(),
);
}
}
and in the screen you're fetching data:
@override
Widget build(BuildContext context) {
final markersProvider = Provider.of<MarkerListProvider >(context);
markerListProvider.loadMarkers().then((value){
//YOUR CODE.
});
.
.
.
}
Also consider using FutureBuilder()
for the widgets based on external data:
FutureBuilder(
future: markerListProvider.loadMarkers(), builder:
(BuildContext context, AsyncSnapshot<List<Marker>> snapshot) {
if (!snapshot.hasData) {
return const Text("No data available");
}
final markers = snapshot.data;
if (markers!.isEmpty) {
return const Text("No data available");;
}
return ListView.builder(
itemCount: markers.length,
itemBuilder: ((context, index) {
return Text(" ${markers[index].text} - ${markers[index].latitude} , ${markers[index].longitude}");
})
);
}
),