Do not use BuildContexts across async gaps

The introduction of the mounted property to BuiltContext in Flutter 3.7 and later versions has made it possible to safely check if a widget is still mounted from anywhere, including within asynchronous methods.

Update: Using mounted with BuildContext

In the updated version of Flutter, the mounted property is now officially added to BuiltContext. This allows developers to check if a widget is still mounted from anywhere, including within asynchronous methods.

class MyCustomClass {
  const MyCustomClass();

  Future myAsyncMethod(BuildContext context) async {
    Navigator.of(context).push(/*waiting dialog */);
    await Future.delayed(const Duration(seconds: 2));
    if (context.mounted) Navigator.of(context).pop();
  }
}

This example demonstrates how to use the mounted property within an asynchronous method. The Navigator.pop() call is only executed if the widget is still mounted.

Original Advice: Handling Async Contexts

The original advice was to avoid storing context directly into custom classes and not use context after an async call if you’re unsure whether your widget is mounted. Here’s how to handle this scenario:

class MyCustomClass {
  const MyCustomClass();

  Future myAsyncMethod(BuildContext context, VoidCallback onSuccess) async {
    await Future.delayed(const Duration(seconds: 2));
    onSuccess.call();
  }
}

This revised method takes an additional VoidCallback parameter that is called after the asynchronous operation has completed. The callback can then safely use the provided context to perform actions such as popping a navigator.

Example Usage: Using mounted with StatefulWidget/StatelessWidget

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State {
  @override
  Widget build(BuildContext context) {
    return IconButton(
      onPressed: () => const MyCustomClass().myAsyncMethod(context, () {
        if (!mounted) return;
        Navigator.of(context).pop();
      }),
      icon: const Icon(Icons.bug_report),
    );
  }
}

This example demonstrates how to use the mounted property within a StatefulWidget. The callback provided to the myAsyncMethod() function checks if the widget is still mounted before popping the navigator.

Using context.mounted with async calls

void foo(BuildContext context) async {
  await someFuture();
  if (!context.mounted) return;
  Navigator.pop(context); // No warnings now
}

This example shows how to use the mounted property within an asynchronous method. The Navigator.pop() call is only executed if the widget is still mounted.

Conclusion

The introduction of the mounted property to BuiltContext in Flutter 3.7 and later versions has made it possible to safely use context within asynchronous methods while ensuring that widgets are not used after they have been unmounted.