1

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,
          ),
        ),
      ),
    );
  }
}
AbdalRahman Farag
  • 197
  • 1
  • 8
  • 18

2 Answers2

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();
}
no_fate
  • 1,625
  • 14
  • 22
  • Thanks for your detailed response. However, I am getting this error on the positionSubscript: A value of type 'StreamSubscription' can't be assigned to a variable of type 'StreamSubscription – AbdalRahman Farag Dec 19 '19 at 13:26
  • Could you update your question and add this line separately? – no_fate Dec 19 '19 at 13:31
  • 1
    Many thanks again..The only change I made is changing the stream subscription type to be 'LocationData' Have a nice day; – AbdalRahman Farag Dec 19 '19 at 13:35
-1

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();
  }
Guru Prasad mohapatra
  • 1,809
  • 13
  • 19
  • You can't do this because you don't have initialized base widget state at the moment when you want to call `initMapState` – no_fate Dec 19 '19 at 13:33
  • Then we should take 2 methods one for fetching location before `super.initState` and another for map initialising after `super.initState`.. – Guru Prasad mohapatra Dec 19 '19 at 13:48
  • there is no problem with position of `super.initState`. > If you override this, make sure your method starts with a call to super.initState(). https://api.flutter.dev/flutter/widgets/State/initState.html – no_fate Dec 19 '19 at 13:50