DEV3 Technologies home

DEV3 Developer Forum

What does "Don't use BuildContext across async gaps" mean in Flutter and how do I fix it?

Flutter helpSolved0 views
dev3 ·

The analyzer warns on this code:

onPressed: () async {
  await api.save(form);
  Navigator.of(context).pop();
}

Is it a real bug or just lint noise?

#flutter#async#lint

0

1 reply

dev3 · Accepted answer

It is a real (if rare) bug

While await api.save() runs, the widget may be removed from the tree (user pressed back, a tab changed, a parent rebuilt). The context you hold then points at a disposed element, and Navigator.of(context) can throw or act on the wrong place.

Fix in a StatefulWidget: check mounted

onPressed: () async {
  await api.save(form);
  if (!mounted) return;
  Navigator.of(context).pop();
}

Fix anywhere (Flutter 3.7+): context.mounted

onPressed: () async {
  await api.save(form);
  if (!context.mounted) return;
  Navigator.of(context).pop();
}

context.mounted works in StatelessWidgets and in helper functions that receive a context.

Fix by capturing before the await

onPressed: () async {
  final navigator = Navigator.of(context);
  final messenger = ScaffoldMessenger.of(context);
  await api.save(form);
  navigator.pop();
  messenger.showSnackBar(const SnackBar(content: Text('Saved')));
}

This is valid because you looked the objects up while the context was certainly alive.

Better: move the logic out of the widget

Let a controller/notifier do the async work and expose state; the widget listens and navigates in response (for example ref.listen in Riverpod or a BlocListener). Then no context is held across the gap.

Pitfalls

  • Checking mounted once is not enough if you await again afterwards; check after each await.
  • Do not silence the lint with // ignore:, the check is cheap and correct.
0

Your reply

Every post is reviewed by DEV3 before it appears. Usually reviewed within 24 hours.

Markdown supported. Use ``` for code blocks. Images are not allowed.