0

I have a map app that uses google_map_flutter package and displays a full screen themed map. My confusion is that when I build the app I receive an unhandled exception for setMapStyle, even though the map displays with the theme.

Unhandled Exception: NoSuchMethodError: The method 'setMapStyle' was called on null. E/flutter (30877): Receiver: null E/flutter (30877): Tried calling: setMapStyle("[\r\n {\r\n \"featureType\": \"landscape\",\r\n \"elementType\": \"geometry\",\r\n.......

The theme is a json file that I load using the code in my initState below.

@override
  void initState() {
    super.initState();
    // Show the campus Map
    getSunData();
    // _showCampusMap();
    WidgetsBinding.instance.addObserver(this);
    // Check location permission has been granted

    PermissionHandler()
        .checkPermissionStatus(PermissionGroup
            .locationWhenInUse) //check permission returns a Future
        .then(_updateStatus); // handling in callback to prevent blocking UI

    rootBundle
        .loadString('assets/themes/map/day/simple_bright.json')
        .then((string) {
      mapStyle = string;
    });

    getUserLocation();
  }

My method for setting the style is here.

// method that is called on map creation and takes a MapController as a parameter
  void _onMapCreated(GoogleMapController controller) async {
    PermissionHandler()
        .checkPermissionStatus(PermissionGroup
            .locationWhenInUse) //check permission returns a Future
        .then(_updateStatus); // handling in callback to prevent blocking UI

    controller.setMapStyle(mapStyle);
  }

Here is my GoogleMap code

_userLocation == null
                  ? Center(
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: <Widget>[
                          CircularProgressIndicator(
                            backgroundColor: Theme.UniColour.primary[900],
                          ),
                          SizedBox(height: 20.0),
                          Text("Retrieving your location..."),
                        ],
                      ),
                    )
                  : GoogleMap(
                      onMapCreated: _onMapCreated,
                      initialCameraPosition: // required parameter that sets the starting camera position. Camera position describes which part of the world you want the map to point at.
                          CameraPosition(
                              target: _userLocation,
                              zoom: _defaultZoom,
                              tilt: _tiltAngle), //LatLng(53.467125, -2.233966)
                      scrollGesturesEnabled: _scrollGesturesEnabled,
                      tiltGesturesEnabled: _tiltGesturesEnabled,
                      compassEnabled: _compassEnabled,
                      rotateGesturesEnabled: _rotateGesturesEnabled,
                      myLocationEnabled: _myLocationEnabled,
                      buildingsEnabled: _buildingsEnabled, // not added to db
                      indoorViewEnabled: _indoorViewEnabled, // not added to db
                      mapToolbarEnabled: _mapToolbarEnabled, // not added to db
                      myLocationButtonEnabled:
                          _myLocationButtonEnabled, // not added to db
                      mapType: _currentMapType,
                      zoomGesturesEnabled: _zoomGesturesEnabled,
                      cameraTargetBounds: CameraTargetBounds(
                        new LatLngBounds(
                          northeast: uniCampusNE,
                          southwest: uniCampusSW,
                        ),
                      ),
                      minMaxZoomPreference:
                          MinMaxZoomPreference(_minZoom, _maxZoom),
                    ),

Any ideas why this exception is occurring, does it need fixing and how would I do that?

[EDIT]

void _updateStatus(PermissionStatus status) {
    if (status != _status) {
      // check status has changed
      setState(() {
        _status = status; // update
        _onMapCreated(controller);
      });
    } else {
      if (status != PermissionStatus.granted) {
        //print("REQUESTING PERMISSION");
        PermissionHandler().requestPermissions(
            [PermissionGroup.locationWhenInUse]).then(_onStatusRequested);
      }
    }
  }

The argument type 'Completer' can't be assigned to the parameter type 'GoogleMapController'.

[/EDIT]

thanks

Andrew Stevenson
  • 578
  • 1
  • 9
  • 23

2 Answers2

0

You need to initialize the Completer class, under your State class write the following:

 Completer<GoogleMapController> _controller = Completer();

Then use the variable _controller when calling setMapStyle:

  void _onMapCreated(GoogleMapController controller) async {
    PermissionHandler()
        .checkPermissionStatus(PermissionGroup
            .locationWhenInUse) //check permission returns a Future
        .then(_updateStatus); // handling in callback to prevent blocking UI

   _controller.setMapStyle(mapStyle);
  }
Peter Haddad
  • 78,874
  • 25
  • 140
  • 134
  • Thanks Peter - this then has a knock on effect in my _updateStatus permission. I tried swapping controller for _controller, but the error remain. Please see my edit above. – Andrew Stevenson Jan 29 '20 at 12:36
  • in setState (within the _updateStatus method) _onMapCreated(controller); – Andrew Stevenson Jan 29 '20 at 14:01
  • did you change what you are passing to the method `onMapCreated`?! – Peter Haddad Jan 29 '20 at 15:13
  • only change the variable here `_controller.setMapStyle(mapStyle);` – Peter Haddad Jan 29 '20 at 15:13
  • No - I kept void _onMapCreated(GoogleMapController controller) async { the same, added Completer _controller = Completer(); and change controller.setMapStyle(mapStyle); to _controller.setMapStyle(mapStyle); – Andrew Stevenson Jan 29 '20 at 15:39
  • I tried switch what I passed from controller to _controller – Andrew Stevenson Jan 29 '20 at 15:40
  • Inside onmapcreatedyou you need to pass a controller of type GoogleMapController – Peter Haddad Jan 29 '20 at 16:52
  • Hi Peter, I've taken another look at this and I receive an error on setMapStyle in the line -> _controller.setMapStyle(_mapTheme); in my onMapCreated method. I am passing GoogleMapControler controller to onMapCreated also. I have noticed this line -> FutureOr get controller => null; which was added by VSCode. I believe this is where the null error is coming from. Using the Completer is simply not working for me. If you have any other ideas, then I would appreciate it. Thanks for your time – Andrew Stevenson Feb 03 '20 at 12:06
0

It is important to mark the Future methods with await for asynchronous processing.

In your _onMapCreated, you can add the future method that loads the mapStyle.

  void _onMapCreated(GoogleMapController controller) async {
    final mapStyle = await rootBundle.loadString(
      'assets/themes/map/day/simple_bright.json',
    );

    await controller.setMapStyle(mapStyle);

    _updateStatus = await PermissionHandler()
        .checkPermissionStatus(
       PermissionGroup.locationWhenInUse
    );
  }
snap
  • 175
  • 1
  • 12