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();
}