ChangeNotifier was used after being disposed

Issue

I am new to Flutter and stuck with this
I have a page that uses a class named GoogleMapsNotifier with ChangeNotifier and when I pop the page I want to dispose the Stream inside this class (last function).

class GoogleMapsNotifier with ChangeNotifier {
  final geolocatorService = GeolocatorService();
  final placesService = PlacesService();
  final markerService = MarkerService();

  Position? currentLocation;
  List<PlaceSearch> searchResults = [];
  StreamController<Place> selectedLocation = BehaviorSubject<Place>();
  StreamController<LatLngBounds> bounds = BehaviorSubject<LatLngBounds>();
  late Place selectedLocationStatic;
  List<Marker> markers = <Marker>[];

  GoogleMapsNotifier() {
    setCurrentLocation();
  }

  setCurrentLocation() async {
    currentLocation = await geolocatorService.determinePosition();
    selectedLocationStatic = Place(
        geometry: Geometry(
          location: Location(
              lat: currentLocation!.latitude, lng: currentLocation!.longitude),
        ),
        name: '',
        vicinity: '');
    notifyListeners();
  }

  searchPlaces(String searchTerm) async {
    searchResults = await placesService.getAutocomplete(searchTerm);
    notifyListeners();
  }

  setSelectedLocation(String placeId) async {
    var sLocation = await placesService.getPlace(placeId);
    selectedLocation.add(sLocation);
    selectedLocationStatic = sLocation;
    searchResults = [];
    markers = [];
    var newMarker = markerService.createMarkerFromPlace(sLocation);
    markers.add(newMarker);
    var _bounds = markerService.bounds(Set<Marker>.of(markers));
    bounds.add(_bounds as LatLngBounds);
    notifyListeners();
  }

  @override
  void dispose() {
    selectedLocation.close();

    super.dispose();
  }
}

and then I have a Go Back button that pops the page and I call this function with Provider before.

onTap: () async {
                    Provider.of<GoogleMapsNotifier>(context, listen: false)
                        .dispose();
                    Navigator.pop(context);
                  },

It works fine for the first time but when I enter the page for the second time and press Go Back button again, it return an error

Unhandled Exception: A GoogleMapsNotifier was used after being
disposed. E/flutter (13173): Once you have called dispose() on a
GoogleMapsNotifier, it can no longer be used.

How can I fix this?

Solution

The Provider should be inside the Route you push. If you use a global provider, the instance of GoogleMapsNotifier will always be the same. Therefore the second time you go on the page it won’t work (since it’s the same instance you already disposed the first time)

Here is a concrete example

// GOOD
runApp(MaterialApp(...));

...

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (_) => ChangeNotifierProvider<GoogleMapsNotifier>(
      create: (_) => GoogleMapsNotifier(),
      child: ...,
    ),
  ),
);


// BAD
runApp(
  ChangeNotifierProvider<GoogleMapsNotifier>(
    create: (_) => GoogleMapsNotifier(),
    child: MaterialApp(
      home: ...,
    ),
  )
);

...

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (_) => ...,
  ),
);

Answered By – Lulupointu

Answer Checked By – Pedro (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *