Flutter set state on loop - flutter

i have a problem with google maps on flutter app, im trying to animate markers iterating marker list with the following method.
Future<void> _iteratePoints() async {
CameraUpdate zoom = CameraUpdate.zoomTo(14);
controller.animateCamera(zoom);
for (final value in listIds) {
await Future.delayed(Duration(seconds: 3));
updatePosition(value);
updateDetailPosition(value);
}
}
Future<void> updateDetailPosition(MarkerAndDetails markerId) async {
print(markerId.toJson().toString());
this.setState(() {
currentlySelectedPin = markerId;
});
}
Future<void> updatePosition(MarkerGlobal markerId) async {
final Marker marker = markers[markerId.markerId];
final LatLng current = marker.position;
var newPosition = CameraPosition(target: LatLng(current.latitude, current.longitude), zoom: 12);
CameraUpdate update = CameraUpdate.newCameraPosition(newPosition);
// CameraUpdate zoom = CameraUpdate.zoomTo(16);
// controller.animateCamera(update);
controller.showMarkerInfoWindow(markerId.markerId);
}
But when im trying on iphone... i have next error:
Unhandled Exception: Concurrent modification during iteration: Instance(length:798) of '_GrowableList'.
I hope someone can help me.

Related

How to add user info above location marker in flutter

I want to display drivers' info above the markers on the map, like driver name and car name. but i do not know how to do so.
I am using flutter, flutter geofire and firebase realtime database
My code is
displayActiveDriversOnUserMap()
{ setState((){
markersSet.clear();
circleSet.clear();
Set<Marker> driversMarkerSet = Set<Marker>();
for(ActiverNearbyAvailableDrivers eachDriver in GeoFireAssistant.activeNearbyAvailableDriversList)
{
LatLng eachDriverActivePosition = LatLng(eachDriver.locationLatitude!, eachDriver.locationLongitude!);
Marker marker = Marker(
markerId: MarkerId(eachDriver.driverId!),
position: eachDriverActivePosition,
icon: activeNearByIcon!,
rotation: 360,
);
driversMarkerSet.add(marker);
}
setState ((){
markersSet = driversMarkerSet;
});
});
}
createActiveNearByDriverIconMarker()
{
if(activeNearByIcon == null)
{
ImageConfiguration imageConfiguration = createLocalImageConfiguration(context, size: const Size(2, 2));
BitmapDescriptor.fromAssetImage(imageConfiguration, "images/car.png").then((value)
{
activeNearByIcon = value;
});
}
}
}
screenshot of map

Assign Future<var> to var

I have some code written in dart where I use the provider package to update the location of a pin on a map. What I would like it to do is have the initial location be equal to the user's current position and then if they drag the pin it will be updated to wherever the pin is dropped.
My problem is that the initial location variable needs to Future<LatLng>, however, when I update the location it ends up being just LatLng and I cannot assign it to the _location variable.
class LocationProvider with ChangeNotifier {
Future<LatLng> _location = LocationService().getLocation();
// Error here, wants it to be Future<LatLng>
LatLng get location => _location;
void calculateNewLocation(oldLocation, zoom, offset) {
var newPoint = const Epsg3857().latLngToPoint(oldLocation, zoom) +
CustomPoint(offset.dx, offset.dy);
LatLng? newLocation = const Epsg3857().pointToLatLng(newPoint, zoom);
// Error here again for the same reason
_location = newLocation ?? _location;
notifyListeners();
}
}
How do I make it so that I can assign both of these values to _location?
You can simply have a method for that in provider file
class LocationProvider with ChangeNotifier {
LatLng? _location;
LatLng? get location => _location;
Future<void> initializeLocation() async {
_location = await LocationService().getLocation();
notifyListeners();
}
void calculateNewLocation(oldLocation, zoom, offset) {
var newPoint = const Epsg3857().latLngToPoint(oldLocation, zoom) +
CustomPoint(offset.dx, offset.dy);
LatLng? newLocation = const Epsg3857().pointToLatLng(newPoint, zoom);
_location = newLocation ?? _location;
notifyListeners();
}
}
Then, you'll have to call initializeLocation when you want it to be initialized, like:
Future<void>? _myFuture;
final _provider = Provider.of<LocationProvider>(listen: false);
_myFuture = _provider.initializeLocation();
and then in FutureBuilder, provide _myFuture in future
PS: ? can be excluded if you're not using dart in null safe mode
Based on your code,
LocationService().getLocation() returns a future, so you have to either await/async or use then().
try these
Future<LatLng> _location = LocationService().getLocation();
LatLng get location = await _location; // put this in a separate method with async keyword
or
LocationService().getLocation().then((value) { location = value } );

GPS off message, and continous location update flutter

i made an app which uses the geolocator package to check for GPS and get the location of the user, and i use the provider package to handle the state. The problem is, when the GPS is switched off, a red screen appears that says the latitude was null, i would like to implement a screen to tell the user to switch on the GPS, and update the location accordingly.
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:geolocator/geolocator.dart';
import 'package:latlong/latlong.dart';
class MapState with ChangeNotifier {
bool locationServiceActive = true;
MapController _mapController;
MapController get mapController => _mapController;
static var _initialPosition;
var _lastPosition = _initialPosition;
LatLng get initialPosition => _initialPosition;
LatLng get lastPosition => _lastPosition;
MapState(){
checkGPS();
_getUserLocation();
}
checkGPS() async{
bool conn = await Geolocator().isLocationServiceEnabled();
if(conn == false){
locationServiceActive = false;
} else {
locationServiceActive = true;
}
notifyListeners();
}
void _getUserLocation() async{
Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
print("/////////////////////////////////////////////////////////////////////////////////position");
print(position);
_initialPosition = LatLng(position.latitude, position.longitude);
notifyListeners();
}
}
update:-
i changed my _getUserLocation function to a stream, which works much better if the user switched on or off the gps (and it uses the last known location if the gps is off)... but it doesn't print the statement in the terminal if the position is null which is weird, only when there is lat and lng!!!
here is the modification i made...
void _getUserLocation() async{
Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
var geolocator = Geolocator();
var locationOptions = LocationOptions(accuracy: LocationAccuracy.high, distanceFilter: 10);
StreamSubscription<Position> positionStream = geolocator.getPositionStream(locationOptions).listen(
(Position position) {
print("/////////////////////////////////////////////////////////////////////////// position");
print(position == null ? 'Unknown' : position.latitude.toString() + ', ' + position.longitude.toString());
});
_initialPosition = LatLng(position.latitude, position.longitude);
notifyListeners();
}
If you want to notify the user about the GPS, you can use something like this
#override
void initState() {
super.initState();
initPlatformState();
location.onLocationChanged.listen((result) {
currentLocation = result;
// your code
});
});
}
void initPlatformState() async {
LocationData currentLocation;
try {
currentLocation = await location.getLocation();
error = "";
} on PlatformException catch (e) {
if (e.code == 'PERMISSION_DENIED')
error = 'Permission Denied';
else if (e.code == 'PERMISSION_DENIED_NEVER_ASK')
error =
'Permission denied - please ask the user to enable it from the app settings';
currentLocation = null;
}
setState(() {
currentLocation = currentLocation;
});
}
Here, you are listening to the location stream if enabled. In case it is not then it throws an error. The package being used here is location

I can't get result of Future

I have this initState:
#override
void initState() {
super.initState();
_initState();
}
_initState() async {
_geIdsList().then((result) {
_idList = result;
print('result $_idList');
}, onError: (e) {
print('error $e');
});
}
Then there's my function to fetch the IDs from Firestore:
Future<List<String>> _geIdsList() async {
List<String> ids = [];
StreamSubscription stream;
Firestore _firestore = Firestore.instance;
Geoflutterfire geo;
var collectionReference = _firestore.collection('locations');
geo = Geoflutterfire();
var location = new Location();
var pos = await location.getLocation();
var radius = BehaviorSubject<double>.seeded(10.0);
GeoFirePoint center = geo.point(latitude: pos.latitude.toDouble(), longitude: pos.longitude.toDouble());
stream = radius.switchMap((rad) {
return geo.collection(collectionRef: collectionReference).within(
center: center, radius: rad, field: 'position', strictMode: true);
}).listen((List<DocumentSnapshot> documentList) {
Future.forEach(documentList, (DocumentSnapshot documentSnapshot) {
print('document here ... $documentSnapshot' );
print(documentSnapshot.data['id']);
var id = documentSnapshot.data['id'].toString();
ids.add(id);
}).whenComplete(() {
stream.cancel();
print('ids from function $ids');
return ids;
});
});
}
Now _getIdsList() is working fine and the
when complete print('ids from function $ids');
line, prints the IDs List and I'm unable to understand why it doesn't work in my initState. Can anyone tell me what's wrong with my code?

How to fix GPS location call currentloaction null error in an API call?

I am calling an Openweather API using current GPS location. But I get an exception showing that currentlocation is called on null.
I can show it on the screen using text widget. But I get null exception when I am calling for the API.
Text('${currentPosition.latitude.toStringAsFixed(2)} ${currentPosition.longitude}'),
void initState() {
getCurrentLocation().then((position) {
currentPosition = position;
});
super.initState();
loadWeather();
}
This the API call function:
Future loadWeather() async {
setState(() {
isLoading = true;
});
final lat = currentPosition.latitude.toStringAsFixed(2);
final lon = currentPosition.longitude.toStringAsFixed(2);
// This part is showing null
final openUviToken = 'API';
final openWeatherToken = 'API';
final weatherResponse = await http.get(
'https://api.openweathermap.org/data/2.5/weather?APPID=${openWeatherToken}&lat=${lat.toString()}&lon=${lon.toString()}');
if (weatherResponse.statusCode == 200) {
return setState(() {
weatherData = new WeatherData.fromJson(
jsonDecode(weatherResponse.body),
);
isLoading = false;
});
}
setState(() {
isLoading = false;
});
}
I tried Hemanth Raj's code already. The app get stuck in a loading state but when I click the button for the loadWeather function, it works. So problem persist only when the app is launched.
This is the load weather button. I just call this function in a column.
IconButton refreshButton() {
return IconButton(
icon: new Icon(Icons.refresh),
tooltip: 'Refresh',
onPressed: loadWeather,
color: Colors.white,
);
}
Seems your are calling loadWeather before the future of getCurrentLocation is complete.
Change your initState like:
void initState() {
getCurrentLocation().then((position) {
currentPosition = position;
loadWeather();
});
super.initState();
}
Hope that helps!