No utilice BuildContexts en espacios asíncronos

Resuelto Bermjly Team asked hace 3 años • 13 respuestas

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
      }
   }
Bermjly Team avatar Aug 21 '21 16:08 Bermjly Team
Aceptado

Actualización de Flutter 3.7+ :

mountedLa 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),
    );
  }
}
Guildem avatar Sep 20 '2021 11:09 Guildem

Usar context.mounted*

En StatefulWidget/ StatelessWidgeto 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 mounteden lugar decontext.mounted

iDecode avatar Aug 13 '2022 06:08 iDecode