Эквивалент смонтированного ChangeNotifier?

Я извлекаю некоторую логику из Stateful Widget в Provider с помощью ChangeNotifier: class Model extends ChangeNotifier {...}

В моем Stateful Widget у меня есть:

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

Как я могу проверить, смонтирован ли виджет в модели?

Например, как я могу позвонить:

 if (mounted) {
notifyListeners();
}

person FlutterFirebase    schedule 26.10.2019    source источник


Ответы (2)


Простой способ - передать «Состояние» вашего виджета с отслеживанием состояния в качестве параметра вашей «Модели».

Как это:

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..
  }
}

Я думаю, вам не нужно проверять, смонтирован State или нет. Вам просто нужно проверить, что модель уже утилизирована. Вы можете переопределить метод dispose() в 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;
  }
}

И не забывайте утилизировать Model, когда удаляется State:

class YourState extends State {
  Model model;

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

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

}

Или вы можете использовать ChangeNotifierProvider в пакете Provider, это поможет вам автоматически удалить Model.

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"),
        ),
      ),
    );
  }

}
person JunYao Yuan    schedule 26.10.2019
comment
Спасибо, у меня была аналогичная проблема при использовании TabController и переключении с вкладки 1 на вкладку 3. При этом вкладка 2 также была инициализирована, и вызов notifyListeners() привел к исключению, поскольку виджет уже был удален. - person anka; 03.11.2019
comment
Попробуйте установить ChangeNotify Disposed вместо State Mount. Я отредактировал ответ для вас. @анка - person JunYao Yuan; 04.11.2019

пока вы оборачиваете свой виджет состоянием модели провайдера, и, как известно, после того, как ваш виджет удален, модель провайдера, которая его обертывает, уже утилизируется по умолчанию

поэтому все, что вам нужно сделать, это определить переменную isDisposed и изменить notifyListeners, как показано ниже.

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;
  }

}
person Karrar    schedule 21.10.2020