简体   繁体   中英

Flutter & Dart : What is mounted for?

I am seeing this mounted syntax. What is it for? Could you give me sample?

TL;DR: A widget is mounted if it has state. If the widget is no longer mounted, ie it has been closed or disposed, its state can no longer be updated. Therefore, we check if a widget is mounted to determine its state can still be updated.

Mounting is the process of creating the state of a StatefulWidget and attaching it to a BuildContext.

Take the following example:

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

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

The widget is assigned its state (_ExampleState) when the createState() method is called.

As soon as it is assigned its state, the widget becomes mounted.

Why is that important?

When a widget is unmounted in the dispose method of a StatefulWidget , it loses its state. This happens when it is no longer in the tree. Ie, it is has been closed, or no longer exists.

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

This basically means the state can't be updated and setState can no longer be called. So when you check if a widget is mounted, you're checking if its state can still be updated.

Use case:

Going back to our example Stateful Widget example, let's say we had a number that we wanted to update 30 seconds after the Widget is created.

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

Our code will work fine, as long as the widget is disposed of or closed. If it is disposed of, we will get the famous error:

setState() called after dispose()

To prevent this, all we have to do is check if our widget still has state before updating it.

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

It represents whether a state is currently in the widget tree.

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

You shouldn't call setState() on a state that is not currently in the tree.

Edit: The other answer provides a simple example. I should also mention that the described behavior is evident from the StatefulWidget lifecycle: https://flutterbyexample.com/lesson/stateful-widget-lifecycle

It's opinionated, but as far as I can see, it's a rare ocasion when you have to check for mounted , because you unsubscribe from outside events in dispose() . Even the Future from the example could be wrapped in CancelableOperation to cancel it in dispose() , which is before mounted == false

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM