cavargov
cavargov

Reputation: 445

Unhandled Exception: A ChangeNotifier was used after being disposed

I'm getting this error message:

Unhandled Exception: A ModeManager was used after being disposed.

I'm using ChangeNotifier (class ModeManager) together with ChangeNotifierProvider. Build method, where I create Provider looks like this:

@override
Widget build(BuildContext context) {
    return !_isLoaded ? Center(child: CircularProgressIndicator()) : ChangeNotifierProvider(
        create: (_) => ModeManager(_appUser),
        child: Scaffold(
            appBar: AppBar(
            title: Text('Connect Spotify'),
            ),
            body: AddSpotifyScreenBody(),
        ),
    );
}

Widget where I use provider looks something like this:

class _AddSpotifyScreenBodyState extends State<AddSpotifyScreenBody> {
  @override
  Widget build(BuildContext context) {
    var provider = Provider.of<ModeManager>(context);
    return Center(
      child: Padding(
        padding: EdgeInsets.all(20.0),
        child: Column(
          children: <Widget>[
            Text(provider.isCollecting ? 'COLLECTING NOW' : 'SHARING NOW'),
            //...some other widgets using provider...
          ],
        ),
      ),
    );
  }
}

Does anybody know what could cause this error or what am I doing wrong? Thank You very much.

Upvotes: 9

Views: 12721

Answers (3)

Mohamed Irshad
Mohamed Irshad

Reputation: 2186

Created an extension for ChangeNotifier based on @ismaeel Sherif's answer. If you are using classes extends ChangeNotifier in multiple places, its safe to use an extension like this.

import 'package:flutter/material.dart';

class DisposeSafeChangeNotifier extends ChangeNotifier {
  bool _disposed = false;

  @override
  void dispose() {
    _disposed = true;
    super.dispose();
  }

  @override
  void notifyListeners() {
    if (!_disposed) {
      super.notifyListeners();
    }
  }
}

extend your class with DisposeSafeChangeNotifier instead of ChangeNotifier.

Upvotes: 1

Ricky
Ricky

Reputation: 103

Override dispose() in Widget cancel whatever work performFetch and expensiveOperation are doing, so that performFetch never actually calls notifyListeners.

You don't need to remove the listener before calling dispose, dispose clears the listener list.

Upvotes: 0

Ismaeel Sherif
Ismaeel Sherif

Reputation: 710

It seems that you call notifyListeners() after disposing the widget with the ChangeNotifierProvider() . This happened with me when a Future function call notifyListeners(). As mentioned here, you can override the notifyListeners method in the ChangeNotifier class :

@override
void dispose() {
  _disposed = true;
  super.dispose();
}

@override
void notifyListeners() {
  if (!_disposed) {
    super.notifyListeners();
  }
}

don't forget to declare the variable bool _disposed = false;

Upvotes: 45

Related Questions