不要跨异步间隙flutter使用BuildContexts

s2j5cfk0  于 2023-01-06  发布在  Flutter
关注(0)|答案(3)|浏览(423)

我创建了一个注册函数,在Utils.flushBarErrorMessage("No Internet", context);上收到Do not use BuildContexts across async gaps.警告。我是flutter新手,想知道如何使用asyncawait

Future _registration() async {
    String name = _nameController.text.trim();
    String email = _emailController.text.trim();
    String password = _passwordController.text.trim();
    String phone = _phoneController.text.trim();

    if (name.isEmpty) {
      Utils.flushBarErrorMessage("Type your name", context);
    } else if (email.isEmpty) {
      Utils.flushBarErrorMessage("Type your email", context);
    } else if (!GetUtils.isEmail(email)) {
      Utils.flushBarErrorMessage("Type valid email address", context);
    } else if (password.isEmpty) {
      Utils.flushBarErrorMessage("Type your password", context);
    } else if (password.length < 6) {
      Utils.flushBarErrorMessage(
          "password can't be less than 6 characters", context);
    } else if (phone.isEmpty) {
      Utils.flushBarErrorMessage("Type your phone", context);
    }
    else {
      var connectivityResult = await (Connectivity().checkConnectivity());
      if (connectivityResult == ConnectivityResult.mobile ||
          connectivityResult == ConnectivityResult.wifi) {
        ApiCall.signUp(name, email, password, phone).then((value) {
          if (value.statusCode == 200) {
            if (json.decode(value.body)['success'] != null) {
              if (json.decode(value.body)["success"]) {
                RegisterResponse registerResponseModel =
                    RegisterResponse.fromJson(json.decode(value.body));
                Navigator.pushNamed(context, VerifyUser.routeName);
                Utils.flushBarErrorMessage(
                    'User Registered Successfully', context);
                if (kDebugMode) {
                  print('User Registered Successfully');
                }
              } else {
                Utils.flushBarErrorMessage(
                    json.decode(value.body)["en_message"], context);
                if (kDebugMode) {
                  print(json.decode(value.body).toString());
                }
              }
            }
          } else {
            Utils.flushBarErrorMessage('invalid data', context);
            if (kDebugMode) {
              print(json.decode(value.body).toString());
            }
          }
        });
      } else {
        Utils.flushBarErrorMessage("No Internet", context);
      }
    }
  }

称之为_registration()

ElevatedButton(
            onPressed: () {
              _registration();
            },
            child: const Text('SignUp')),

这是我的flushBarErrorMessage

class Utils {
  static void flushBarErrorMessage(String message, BuildContext context) {
    showFlushbar(
        context: context,
        flushbar: Flushbar(
          forwardAnimationCurve: Curves.decelerate,
          margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
          padding: const EdgeInsets.all(15),
          titleColor: Colors.white,
          duration: const Duration(seconds: 3),
          borderRadius: BorderRadius.circular(10),
          reverseAnimationCurve: Curves.easeInOut,
          icon: const Icon(
            Icons.error,
            size: 28,
            color: Colors.white,
          ),
          flushbarPosition: FlushbarPosition.TOP,
          positionOffset: 20,
          message: message,
          backgroundColor: Colors.red,
        )..show(context));
  }
}
7xzttuei

7xzttuei1#

问题是在await之后,每次使用BuildContext都会显示此警告。出现此警告是因为在await之后使用BuildContext可能会在小部件被处置后发生。这样,上下文将不再存在,应用甚至可能因此崩溃。查看the official lint documentation
存储BuildContext供以后使用很容易导致难以诊断的崩溃。异步间隙隐式存储BuildContext,是编写代码时最容易忽略的一些间隙。
从官方文档中可以找到简单的解决方案,即需要检查State.mounted,在出现警告的每个地方,代码都是这样的:

...
      } else {
        if (mounted) Utils.flushBarErrorMessage("No Internet", context);
      }
      ...
5f0d552i

5f0d552i2#

试试这个:

///Add context
Future _registration(BuildContext context) async {
...
if(!mounted) return;
 Navigator.pushNamed(context, VerifyUser.routeName);
...
}

呼叫时:

ElevatedButton(
            onPressed: () {
             //make sure your class is of StatefulWidget()
              _registration(context); ///Add context
            },
            child: const Text('SignUp')),
qc6wkl3g

qc6wkl3g3#

对此警告的最简单回答是:

    • 一月一日**

await关键字之前保留对context用法的引用。
示例:

// navigation
onPressed: () async {
    final router = GoRouter.of(context);

    final result = await [
        Permission.location,
        Permission.locationAlways,
        Permission.locationWhenInUse
    ].request();

    if (...) {
        router.go(AppRouter.dashboard);
    } else {
        router.go(AppRouter.askForCustomLocation);
    }

// cubit
onPressed: () async {

    final appSettingsCubit = BlocProvider.of<AppSettingsCubit>(context);

    final result = await [
        Permission.location,
        Permission.locationAlways,
        Permission.locationWhenInUse
    ].request();

    if (...) {
        appSettingsCubit.locationProptAsked();
    } else {
        appSettingsCubit.locationProptAsked();
    }
    • 一米三米一x**

只需使用if(mounted)逻辑 Package context用法
示例:

// navigation
onPressed: () async {    
    final result = await [
        Permission.location,
        Permission.locationAlways,
        Permission.locationWhenInUse
    ].request();

    if (...) {
        if(mounted) {
            router.go(AppRouter.dashboard);
        }
    } else {
        if(mounted) {
            router.go(AppRouter.dashboard);
        }
    }

// cubit
onPressed: () async {
    final result = await [
        Permission.location,
        Permission.locationAlways,
        Permission.locationWhenInUse
    ].request();

    if (...) {
        if(mounted) {
            BlocProvider.of<AppSettingsCubit>(context).locationProptAsked();
        }
    } else {
        if(mounted) {
            BlocProvider.of<AppSettingsCubit>(context).locationProptAsked();
        }
    }

这都是我的经验。

相关问题