7

I am extract some logic from Stateful Widget to Provider with ChangeNotifier: class Model extends ChangeNotifier {...}

In my Stateful Widget I have:

if (mounted) {
  setState(() {});
}

How I can check if Widget is mounted in Model?

For example how I can call:

if (mounted) {
  notifyListeners();
}
spydon
  • 9,372
  • 6
  • 33
  • 63
FlutterFirebase
  • 2,163
  • 6
  • 28
  • 60

4 Answers4

8

A simple way is pass 'State' of your Stateful Widget as a parameter to your 'Model'.

Like this:

class Model extends ChangeNotifier {

  Model(this.yourState);

  YourState yourState;

  bool get _isMounted => yourState.mounted;
}

class YourState extends State<YourStatefulWidget> {
  Model model;

  @override
  void initState() {
    super.initState();
    model = Model(this);
  }

  @override
  Widget build(BuildContext context) {
    // your code..
  }
}

I think you don't need to check the State is mounted or not. You just need to check the Model has been already disposed. You can override dispose() method in ChangeNotifier:

class Model extends ChangeNotifier {
  bool _isDisposed = false;

  void run() async {
    await Future.delayed(Duration(seconds: 10));
    if (!_isDisposed) {
      notifyListeners();
    }  
  }

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

And don't forget dispose Model when the State is disposed:

class YourState extends State {
  Model model;

  @override
  void initState() {
    super.initState();
    model = Model();
  }

  @override
  void dispose() {
    model?.dispose();
    super.dispose();
  }
  /// Your build code...

}

Or you can use ChangeNotifierProvider in package Provider, it will help you to dispose Model automatically.

class YourState extends State {
  Model model;

  @override
  void initState() {
    super.initState();
    model = Model();
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<Model>(
      builder: (build) => model,
      child: Container(
        child: Consumer<Model>(
          builder: (context, model, widget) => Text("$model"),
        ),
      ),
    );
  }

}
JunYao Yuan
  • 223
  • 1
  • 6
  • Thanks, I had a similar problem when using `TabController` and switching from tab 1 to tab 3. When doing this, the tab 2 was initialized too and calling `notifyListeners()` resulted in an exception because the widget was disposed already. – anka Nov 03 '19 at 19:04
  • 1
    Try check ChangeNotify disposed instead of State mounted. I have edited the answer for you. @anka – JunYao Yuan Nov 04 '19 at 10:19
0

as long as you wrap your widget with the provider model state and as it is known once your widget is disposed the provider model that is wrapping it already get disposed by default

so all you have to do is to define a variable isDisposed and modify the notifyListeners as below

MyState with ChangeNotifier{

// to indicate whether the state provider is disposed or not
 bool _isDisposed = false;


   // use the notifyListeners as below
   customNotifyListeners(){
    if(!_isDisposed){
       notifyListeners()
    }
   }




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

}
Karrar
  • 1,273
  • 3
  • 14
  • 30
0

Just use a custom ChangeNotifier class.

import 'package:flutter/cupertino.dart';

class CustomChangeNotifier extends ChangeNotifier {
  bool isDisposed = false;

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

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

you can just override notifyListeners like this

class Model extends ChangeNotifier { 

    @override
    void notifyListeners() {
        WidgetsBinding.instance.addPostFrameCallback((t) {
            print("skip notify after ${t.inMilliseconds}ms");
            super.notifyListeners();
        });

    }

}

no need additional variables / constructor modification

nashihu
  • 750
  • 7
  • 17