LateInitializationError: Field 'currentLatLng' has not been initialized in Flutter - flutter

I am displaying my current location on google maps using this library: package:location/location.dart. Pub Dev Link
The problem is whenever I open the app in release mode it crashes and shows:
LateInitializationError: Field 'currentLatLng' has not been
initialized
It does not crash in debug mode on an Android Device.
It does, however, crash on iOS (release and debug mode).
I am not sure what I am doing wrong. Here's my widget and attempt:
class TestGoogle extends StatefulWidget {
const TestGoogle({Key? key}) : super(key: key);
#override
_TestGoogleState createState() => _TestGoogleState();
}
class _TestGoogleState extends State<TestGoogle> {
late LatLng currentLatLng;
late GoogleMapController mapController;
Location location = new Location();
var latitude;
var longitude;
late LocationData _locationData;
get() async {
_locationData = await location.getLocation();
latitude = _locationData.latitude;
longitude = _locationData.longitude;
setState(() {
currentLatLng = new LatLng(latitude, longitude);
});
}
#override
initState() {
super.initState();
get();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: GoogleMap(
myLocationEnabled: true,
onCameraMove: (CameraPosition cameraPosition) {
print(cameraPosition.zoom);
},
initialCameraPosition:
CameraPosition(target: currentLatLng, zoom: 15.0),
),
);
}
}

The below codes should fix your problem. Your problem reason, try use variable before initializing.
class TestGoogle extends StatelessWidget {
TestGoogle({Key? key}) : super(key: key);
late GoogleMapController mapController;
Location location = Location();
Future<LatLng> get() async {
final _locationData = await location.getLocation();
return LatLng(_locationData.latitude, _locationData.longitude);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<LatLng>(
future: get(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final locationModel = snapshot.data!;
final latitude = locationModel.latitude;
final longitude = locationModel.longitude;
return GoogleMap(
myLocationEnabled: true,
onCameraMove: (CameraPosition cameraPosition) {
print(cameraPosition.zoom);
},
initialCameraPosition: CameraPosition(target: locationModel, zoom: 15.0),
);
}
return const CircularProgressIndicator();
},
),
);
}
}

I Fixed this by
class TestGoogle extends StatefulWidget {
const TestGoogle({Key? key}) : super(key: key);
#override
_TestGoogleState createState() => _TestGoogleState();
}
class _TestGoogleState extends State<TestGoogle> {
LatLng? currentLatLng;
late GoogleMapController mapController;
Location location = new Location();
var latitude;
var longitude;
late LocationData _locationData;
get() async {
_locationData = await location.getLocation();
latitude = _locationData.latitude;
longitude = _locationData.longitude;
setState(() {
currentLatLng = new LatLng(latitude, longitude);
});
}
#override
initState() {
super.initState();
get();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: currentLatLng == null
? Center(child: PlatformCircularProgressIndicator())
: GoogleMap(
myLocationEnabled: true,
onCameraMove: (CameraPosition cameraPosition) {
print(cameraPosition.zoom);
},
initialCameraPosition:
CameraPosition(target: currentLatLng, zoom: 15.0),
),
);
}
}

Related

Flutter Google Maps errror

Im just building a google maps with flutter 2.8.1 and google_maps_flutter: ^2.1.4, everytime i save/hot reload it give me this error not always but quite often and im afraid this will cause big problem in future.
note: i cannot change the flutter and maps version because i have to use this version
throw PlatformException(code: errorCode, message: errorMessage as String?, details: errorDetails, stacktrace: errorStacktrace);
this is the full error code
#override
dynamic decodeEnvelope(ByteData envelope) {
// First byte is zero in success case, and non-zero otherwise.
if (envelope.lengthInBytes == 0)
throw const FormatException('Expected envelope, got nothing');
final ReadBuffer buffer = ReadBuffer(envelope);
if (buffer.getUint8() == 0)
return messageCodec.readValue(buffer);
final Object? errorCode = messageCodec.readValue(buffer);
final Object? errorMessage = messageCodec.readValue(buffer);
final Object? errorDetails = messageCodec.readValue(buffer);
final String? errorStacktrace = (buffer.hasRemaining) ? messageCodec.readValue(buffer) as String? : null;
if (errorCode is String && (errorMessage == null || errorMessage is String) && !buffer.hasRemaining)
throw PlatformException(code: errorCode, message: errorMessage as String?, details: errorDetails, stacktrace: errorStacktrace);
else
throw const FormatException('Invalid envelope');
}
this is my full code
class MapScreen extends StatefulWidget {
const MapScreen({Key? key}) : super(key: key);
#override
State<MapScreen> createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
late GoogleMapController mapController;
final LatLng _center = const LatLng(45.521563, -122.677433);
static const CameraPosition _initialCameraPosition = CameraPosition(
target: LatLng(37.42796133580664, -122.085749655962),
zoom: 14.4746,
);
#override
void dispose() {
// TODO: implement dispose
super.dispose();
mapController.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppBarr(),
floatingActionButton: _buildCustomFab(),
body: GoogleMap(
mapType: MapType.normal,
myLocationButtonEnabled: false,
zoomControlsEnabled: false,
initialCameraPosition: _initialCameraPosition,
onMapCreated: (controller) => mapController = controller,
),
);
}
}

Flutter Google maps not reloading after changing markers

I'm working with the google map widget, when I render the map for the first time with static markers it displays all the markers, but when I get the data from API and try to add new markers to the map, it won't display them.
below the code that i'm using :
class Map extends StatefulWidget {
final Position initialPosition;
final List<Marker> allSitesMarkers;
final List<Site> placesSite;
final List<String> mapMarkersCategories;
const Map(this.initialPosition, this.allSitesMarkers, this.placesSite,
this.mapMarkersCategories,
{Key key})
: super(key: key);
#override
State<StatefulWidget> createState() => MapState();
}
class MapState extends State<Map> {
Completer<GoogleMapController> _controller = Completer();
String currentCategoryFilter;
bool filtred = false;
Set<Marker> _markers = Set();
List<Marker> markersToShow;
#override
void initState() {
super.initState();
refreshMarkers();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: (widget.placesSite.isNotEmpty)
? Stack(
children: [
GoogleMap(
initialCameraPosition: const CameraPosition(
target: LatLng(36.798, 10.1717), zoom: 15),
mapType: MapType.normal,
myLocationEnabled: true,
markers: _markers,
onMapCreated: (GoogleMapController controller) {
controller.setMapStyle(
'[ //... ]');
_controller.complete(controller);
},
),
_chips()
],
)
: const NoListMap(),
);
}
Widget _chips() {
//..
}
filterSites(String category) {
setState(() {
_markers.clear();
filtred = true;
markersToShow = widget.allSitesMarkers
.where((element) => element.infoWindow.title == category)
.toList();
});
refreshMarkers();
}
refreshMarkers() {
if (filtred) {
setState(() {
_markers.clear();
_markers.addAll(markersToShow);
});
} else {
setState(() {
_markers.clear();
_markers.addAll(widget.allSitesMarkers);
});
}
}
}
I'm using:
Flutter 2.10.2
Dart 2.16.1
google_maps_flutter : 2.0.9
Your _markers is a Set, and in setState you use clear and addAll to empty it and to add new items to the set. But the value of _markers does not change when you do so, therefore it will not trigger a rebuild.
This happens because _markers holds a reference to the Set (like lists, objects etc.).
You need to assign a new value to _markers to trigger a rebuild, for example:
setState(() {
_markers = markersToShow.toSet();
});
This will actually change the reference kept in _markers.

how i can use google map to get current location or choose location?

i start with this code but all what i get white screen
how i can use google map to get current location or choose location.I am using GoogleMap package in flutter to get the required current location.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget { #override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Google Maps Demo', home: MapSample(), ); } }
class MapSample extends StatefulWidget { #override
State createState() => MapSampleState();
}
class MapSampleState extends State {
Completer _controller = Completer();
static final CameraPosition _kGooglePlex = CameraPosition( target:
LatLng(37.42796133580664, -122.085749655962), zoom: 14.4746, );
static final CameraPosition _kLake = CameraPosition( bearing:
192.8334901395799, target: LatLng(37.43296265331129,
-122.08832357078792), tilt: 59.440717697143555, zoom:
19.151926040649414);
#override Widget build(BuildContext context) { return new Scaffold(
body: GoogleMap(
mapType: MapType.hybrid, initialCameraPosition: _kGooglePlex,
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
floatingActionButton:
FloatingActionButton.extended(
onPressed: _goToTheLake,
label:
Text('To the lake!'),
icon: Icon(Icons.directions_boat), ),
);
}
Future _goToTheLake() async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(_kLake));
}
}
If you're using Url properly(no spelling/parameter mistakes) with API key and there's no error from the server which happens a lot due to restrictions. Then there are other steps you need to, ask Location permission on app loading using https://pub.dev/packages/permission_handler package like this.
Code can be something like this.
Create an app_persmission_provider file.
class AppPermissionProvider with ChangeNotifier {
PermissionStatus _locationStatus = PermissionStatus.denied;
LatLng? _locationCenter;
final location_package.Location _location =
location_package.Location();
location_package.LocationData? _locationData;
// Getter
get locationStatus => _locationStatus;
get locationCenter => _locationCenter;
get location => _location;
void getLocationStatus() async {
final status = await Permission.location.request();
_locationStatus = status;
notifyListeners();
print(_locationStatus);
}
void getLocation() async {
_locationData = await _location.getLocation();
_locationCenter = LatLng(
_locationData!.latitude as double, _locationData!.longitude as double);
notifyListeners();
}
}
Then declare the provider on the root maybe, and In my case, I'm initializing some functions onInit. By doing so, android will ask for permission for location when your page loads.
#override
void initState() {
super.initState();
appPermission = Provider.of<AppPermissionProvider>(context, listen: false);
appPermission.getLocationStatus();
appPermission.getLocation();
}
And then using consumer.
SafeArea(
child: Consumer<AppPermissionProvider>(
builder: (context, appPermissionProvider, _) => appPermission
.locationCenter ==
null
? const Center(child: CircularProgressIndicator())
:
GoogleMap( myLocationButtonEnabled:
appPermissionProvider.locationStatus ==
PermissionStatus.granted
? true
: false,
myLocationEnabled: true,
initialCameraPosition: CameraPosition(
target: appPermission.locationCenter,
zoom: 14,
),
onMapCreated: onMapCreated,
mapType: MapType.normal,
compassEnabled: true,
),
),
)
Here, I am checking if permission is granted, also I am only enabling myLocationButton if location permission is granted.
You can use google_maps_flutter package ,
A short example how you can use it.
For more clearity you can visit
Here or you can use geolocator.
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
LatLng _initialcameraposition = LatLng(20.5937, 78.9629);
GoogleMapController _controller;
Location _location = Location();
void _onMapCreated(GoogleMapController _cntlr)
{
_controller = _cntlr;
_location.onLocationChanged.listen((l) {
_controller.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(target: LatLng(l.latitude, l.longitude),zoom: 15),
),
);
});
}

cant set my location on flutter google maps

I am newbie in flutter, I am trying to set my location as the center point of the map that the app draw on the screen
I am using statefulwidget as the root of my app and add this code :
class MyMap extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MyMapState();
}
}
class MyMapState extends State<MyMap> {
GoogleMapController googleMapController;
LocationData currentLocation;
LocationData distinationLocation;
Location location;
#override
void initState() {
location = Location();
setInitSourceAndDestination();
super.initState();
}
setInitSourceAndDestination() async {
currentLocation = await location.getLocation();
}
#override
Widget build(BuildContext context) {
CameraPosition initialCameraPosition = CameraPosition(
target: LatLng(currentLocation.latitude, currentLocation.longitude),);
return GoogleMap(
initialCameraPosition: initialCameraPosition,
onMapCreated: (GoogleMapController controller) => googleMapController = controller,
mapType: MapType.normal,
tiltGesturesEnabled: false,
compassEnabled: true,
myLocationEnabled: true,
);
}
}
But there are a problem I can not solve:
the map is drawn in the screen before currentLocation is set
I tried setState and the problem has not been solved.
How can I make the app draw the map after setInitSourceAndDestination method finish excuting?
What make me confused is that the code at this form the build method will be excuted before setInitSourceAndDestination method finished, but if I add setState and change the currentLocation value inside it to rebuild the screen I noticed that setState executed before build function but it still dont show my location
Add a condition to check the state. If the state is null, then draw a loading indicator. If not null, draw the maps
it can be look like this :
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';
class MapScreen extends StatefulWidget {
#override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
double lat;
double long;
LatLng _pickedLoc;
Future _getLocation() async {
LocationData location = await Location().getLocation();
setState(() {
lat = location.latitude;
long = location.longitude;
});
}
_selectLocation(LatLng location) {
_pickedLoc = location;
}
#override
void initState() {
super.initState();
_getLocation();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: lat == null || long == null
? Center(
child: CircularProgressIndicator(),
)
: GoogleMap(
initialCameraPosition: CameraPosition(
zoom: 16,
target: LatLng(lat, long),
),
onTap: _selectLocation,
onCameraMove: (object) => {debugPrint(object.target.toString())},
markers: {
Marker(
markerId: MarkerId("m1"),
position: _pickedLoc,
)
},
),
);
}
}

Flutter get user location real time error: The setter 'latitude' was called on null

I am new to fultter. I am trying to get real time of user's location. For this, I used the location plugin (https://pub.dev/packages/location).
The issue is that the map is being populated before the location get assigned, and returning an error:
The setter 'latitude' was called on null.
This is the main dart:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:location/location.dart';
import './models/userLocation.dart';
void main() => runApp(Maps());
class Maps extends StatefulWidget {
#override
_MapsState createState() => _MapsState();
}
class _MapsState extends State<Maps> {
LocationData currentLocation;
UserLocation _currentLocation;
var location = new Location();
String error;
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
}
GoogleMapController mapController;
void initState() {
super.initState();
initMapState();
}
initMapState() async {
try {
var userLocation = await location.getLocation();
_currentLocation = UserLocation(
latitude: userLocation.latitude,
longitude: userLocation.longitude,
);
} on PlatformException catch (e) {
if (e.code == 'PERMISSION_DENIED') {
error = 'Permission denied';
}
return _currentLocation;
}
location.onLocationChanged().listen((LocationData currentLocation) {
print(currentLocation.latitude);
print(currentLocation.longitude);
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Create new trip'),
backgroundColor: Colors.green[700],
),
body: GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: CameraPosition(
target:
LatLng(_currentLocation?.latitude,_currentLocation?.longitude),
zoom: 11.0,
),
),
),
);
}
}
Below is the location model:
class UserLocation {
double latitude;
double longitude;
UserLocation({this.latitude, this.longitude});
}
Appreciate your support.
Thanks,
Edit:
Updated Working file:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:location/location.dart';
import './models/userLocation.dart';
void main() => runApp(Maps());
class Maps extends StatefulWidget {
#override
_MapsState createState() => _MapsState();
}
class _MapsState extends State<Maps> {
Location location = new Location();
UserLocation userLocation;
StreamSubscription<LocationData> positionSubscription;
UserLocation _currentLocation;
String error;
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
}
GoogleMapController mapController;
#override
void initState() {
super.initState();
positionSubscription = location
.onLocationChanged()
.handleError((error) => print(error))
.listen(
(newPosition) => setState(() {
_currentLocation = UserLocation(
latitude: newPosition.latitude,
longitude: newPosition.longitude,
);
}),
);
}
#override
void dispose() {
positionSubscription?.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Create new trip'),
backgroundColor: Colors.green[700],
),
body: GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: CameraPosition(
target:
LatLng(_currentLocation.latitude,_currentLocation.longitude),
zoom: 11.0,
),
),
),
);
}
}
So, because of your initState is not using #override this method is
not called
You can't use async calls in onInit callback. It is wrong. Again, you
missed #override.
According to docs You don't need to call getLocation because you
already have a subscription for locations.
Ideally, you need something like this:
UserLocation userPosition;
StreamSubscription<LocationData> positionSubscription;
#override
void initState() {
super.initState();
positionSubscription = location
.onLocationChanged()
.handleError((error) => print(error))
.listen(
(newPosition) => setState(() {
_currentLocation = UserLocation(
latitude: newPosition.latitude,
longitude: newPosition.longitude,
);
}),
);
}
#override
void dispose() {
positionSubscription?.cancel();
super.dispose();
}
write the super.initState() after the initMapState(); because after calling super.initState() The build() is directly called and will not wait for the initMapState() to complete its execution
void initState() {
initMapState();
super.initState();
}