Unhandled Exception: A ChangeNotifier was used after being disposed
Asked Answered
B

3

9

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.

Bromleigh answered 14/9, 2020 at 12:46 Comment(1)
Restart the app and see if it works or not. Also, check provider properly initialized or notEssie
R
45

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;

Reitman answered 15/11, 2020 at 9:12 Comment(3)
Any idea how one could go about debugging this if dispose() is never called on the ChangeNotifier? At least the print statement in there never prints.Palatine
@BrunoEly , Check if the ChangeNotifier is declared as a global provider or it's ChangeNotifierProvider is still in the widget treeReitman
You can also use safe_change_notifier from Canonical if you don't want to do this override yourself.Mckinzie
O
1

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.

Outset answered 23/2 at 16:42 Comment(0)
M
0

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.

Marvismarwin answered 30/12, 2022 at 18:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.