不要跨异步间隙使用 BuildContexts

Do not use BuildContexts across async gaps

我注意到我的项目中有一个新的 lint 问题。

长话短说:

我需要在自定义中使用 BuildContext 类

flutter lint 工具在与 aysnc 方法一起使用时不满意。

示例:

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

进行此更改:

MyCustomClass{
  final buildContext context;
  const MyCustomClass({required this.context});

  myAsyncMethod() async {
    await someFuture();
    # if (!mounted) return;    
    Future.delayed(Duration.zero).then((_) {
      Navigator.of(context).pop();
    });
  }
}

不要将上下文直接存入自定义 类,如果您不确定您的小部件是否已安装,请不要在异步后使用上下文。

做这样的事情:

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

只需将导航器或任何需要上下文的内容保存到函数开头的变量

      myAsyncMethod() async {
        final navigator = Navigator.of(context); // 1
        await someFuture();
        navigator.pop();  // 2
      }

请勿在异步间隙中使用 BuildContext。

存储 BuildContext 供以后使用很容易导致难以诊断的崩溃。异步间隙隐式存储 BuildContext,是编写代码时最容易忽略的部分。

当从 StatefulWidget 使用 BuildContext 时,必须在异步间隙后检查已安装的 属性。

所以,我想,你可以这样使用:

好:

class _MyWidgetState extends State<MyWidget> {
  ...

  void onButtonTapped() async {
    await Future.delayed(const Duration(seconds: 1));

    if (!mounted) return;
    Navigator.of(context).pop();
  }
}

差:

void onButtonTapped(BuildContext context) async {
  await Future.delayed(const Duration(seconds: 1));
  Navigator.of(context).pop();
}