No utilice BuildContexts en espacios asíncronos
He notado un nuevo problema de pelusa en mi proyecto.
Larga historia corta:
Necesito usar BuildContext en mis clases personalizadas
La herramienta Flutter Lint no está contenta cuando se usa con el método aysnc.
Ejemplo:
MyCustomClass{
final buildContext context;
const MyCustomClass({required this.context});
myAsyncMethod() async {
await someFuture();
# if (!mounted) return; << has no effect even if i pass state to constructor
Navigator.of(context).pop(); # << example
}
}
Actualización de Flutter 3.7+ :
mounted
La propiedad ahora se agregó oficialmente a BuildContext
, por lo que puede verificarla desde cualquier lugar, ya sea que provenga de un estado StatefulWidget o de un widget sin estado.
Si bien almacenar contexto en clases externas sigue siendo una mala práctica, ahora puedes comprobarlo de forma segura después de una llamada asíncrona como esta:
class MyCustomClass {
const MyCustomClass();
Future<void> myAsyncMethod(BuildContext context) async {
Navigator.of(context).push(/*waiting dialog */);
await Future.delayed(const Duration(seconds: 2));
if (context.mounted) Navigator.of(context).pop();
}
}
// Into widget
@override
Widget build(BuildContext context) {
return IconButton(
onPressed: () => const MyCustomClass().myAsyncMethod(context),
icon: const Icon(Icons.bug_report),
);
}
// Into widget
Respuesta original
No almacene contexto directamente en clases personalizadas y no use contexto después de async si no está seguro de que su widget esté montado.
Haz algo como esto:
class MyCustomClass {
const MyCustomClass();
Future<void> myAsyncMethod(BuildContext context, VoidCallback onSuccess) async {
await Future.delayed(const Duration(seconds: 2));
onSuccess.call();
}
}
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
@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),
);
}
}
Usar context.mounted
*
En StatefulWidget
/ StatelessWidget
o en cualquier clase que tenga BuildContext
:
void foo(BuildContext context) async {
await someFuture();
if (!context.mounted) return;
Navigator.pop(context); // No warnings now
}
* Si estás en un StatefulWidget
, también puedes usar just mounted
en lugar decontext.mounted