Flutter

#flutter #dart

#flutter #dart

Вопрос:

Я вижу этот mounted синтаксис. Для чего это нужно? Не могли бы вы дать мне образец?

Ответ №1:

TL; DR: виджет монтируется, если у него есть состояние. Если виджет больше не монтируется, т.Е. Он был закрыт или удален, его состояние больше не может быть обновлено. Поэтому мы проверяем, смонтирован ли виджет, чтобы определить, что его состояние все еще можно обновить.

Монтирование — это процесс создания состояния StatefulWidget и прикрепления его к BuildContext .

Возьмем следующий пример:

 class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  @override
  Widget build(BuildContext context) {
    return Container(
      
    );
  }
}
 

Виджету присваивается его состояние (_ExampleState) при createState() вызове метода.

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

Почему это важно?

Когда виджет размонтируется в методе dispose a StatefulWidget , он теряет свое состояние. Это происходит, когда его больше нет в дереве. Т.е. он закрыт или больше не существует.

  @override
  void unmount() {
    super.unmount();
    state.dispose();
    assert(() {
      if (state._debugLifecycleState == _StateLifecycle.defunct)
        return true;
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('${state.runtimeType}.dispose failed to call super.dispose.'),
        ErrorDescription(
          'dispose() implementations must always call their superclass dispose() method, to ensure '
         'that all the resources used by the widget are fully released.'
        ),
      ]);
    }());

    // This is the key
    state._element = null;
  }
 

Это в основном означает, что состояние не может быть обновлено, и setState больше не может быть вызван. Поэтому, когда вы проверяете, смонтирован ли виджет, вы проверяете, можно ли обновить его состояние.

Пример использования:

Возвращаясь к нашему примеру виджета с отслеживанием состояния, допустим, у нас был номер, который мы хотели обновить через 30 секунд после создания виджета.

 class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  int count = 0;

  @override
  void initState() {
    Future.delayed(const Duration(seconds: 30), () {
      setState(() => count = 5);
    });
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: Text('count $count'),
    ));
  }
}
 

Наш код будет работать нормально, пока виджет удален или закрыт. Если он будет удален, мы получим известную ошибку:

 setState() called after dispose()
 

Чтобы предотвратить это, все, что нам нужно сделать, это проверить, есть ли у нашего виджета состояние, прежде чем обновлять его.

   @override
  void initState() {
    Future.delayed(const Duration(seconds: 30), () {
      if (mounted) setState(() => count = 5);
    });
    super.initState();
  }
 

Комментарии:

1. Отличное объяснение, большое спасибо, что поделились им!

Ответ №2:

Он показывает, находится ли состояние в данный момент в дереве виджетов.

https://api.flutter.dev/flutter/widgets/State/mounted.html

Вы не должны вызывать setState() состояние, которого в данный момент нет в дереве.

Редактировать: В другом ответе приведен простой пример. Я должен также упомянуть, что описанное поведение видно из жизненного цикла StatefulWidget: https://flutterbyexample.com/lesson/stateful-widget-lifecycle

Это самоуверенно, но, насколько я вижу, это редкий случай, когда вам нужно проверять mounted , потому что вы отказываетесь от подписки на внешние события dispose() . . Даже будущее из примера может быть обернуто, CancelableOperation чтобы отменить его dispose() , что перед mounted == false