当前位置: 首页 > 知识库问答 >
问题:

颤振异步等待未按预期工作

麻茂材
2023-03-14

自从我开始使用Flatter以来,我面临着一个与Flatter async await相关的问题。大多数时候,我试图用未来和等待的结果,它跳过等待,并得到最短的方式返回如果我尝试在wait之后打印,则先打印空值,然后调用wait

这是我的密码

 onPressed: () async {
                  if (_textEditingController.text.isNotEmpty) {
                    Map a = await Authentication.sendOtp(
                        phoneNum: _textEditingController.text);
                    print(a);
                  }
                },

和我的身份验证类:

class Authentication {
 static Future<Map> sendOtp({required String phoneNum}) async {
    String? vid;
    try {
      if (!kIsWeb) {
        await FirebaseAuth.instance.verifyPhoneNumber(
          phoneNumber: phoneNum,
          verificationCompleted: (PhoneAuthCredential credential) {},
          verificationFailed: (FirebaseAuthException e) {},
          timeout: const Duration(seconds: 5),
          codeSent: (String verificationId, int? resendToken) {
            print('Code Sent $verificationId');
            vid = verificationId;
          },
          codeAutoRetrievalTimeout: (String verificationId) {},
        );
      } else {
        final recaptchaVerifier = RecaptchaVerifier(
            container: null,
            size: RecaptchaVerifierSize.compact,
            theme: ThemeMode.system as RecaptchaVerifierTheme);
        await FirebaseAuth.instance
            .signInWithPhoneNumber(phoneNum, recaptchaVerifier)
            .then((confirmationResult) {
          vid = confirmationResult.verificationId;
        });
      }
      return {'msg': vid, 'val': false};
    } on FirebaseAuthException catch (e) {
      print('------${e.code}');
      return {'msg': e.code, 'val': true};
    } catch (e) {
      print(e);
      return {'msg': null, 'val': true};
    }
  }
}

我得到的输出:

I/flutter (14230): {msg: null, val: false}
E/zzf     (14230): Problem retrieving SafetyNet Token: 7: 
W/System  (14230): Ignoring header X-Firebase-Locale because its value was null.
W/System  (14230): A resource failed to call end. 
W/System  (14230): A resource failed to call end. 
D/EGL_emulation(14230): eglCreateContext: 0xef618f80: maj 2 min 0 rcv 2
E/zzf     (14230): Failed to get reCAPTCHA token with error [The web operation was canceled by the user.]- calling backend without app verification
I/FirebaseAuth(14230): [FirebaseAuth:] Preparing to create service connection to fallback implementation
W/System  (14230): Ignoring header X-Firebase-Locale because its value was null.
I/flutter (14230): Code Sent AJOnW4ROl1S4AeDErwZgls2LAxaQuwURrzDMJ1WNjQH8hWce-BTUeUE21JyCvHpMvfxT4TA8Hcp-mSWFqlzzX-IEd7X6z8ry1mkeCHC7u_ir-lnBL89OP0M6-4kU7BlOKcMPBY5OT4pmpdjETCoyAhrdc8TBR8yJqw
W/FirebaseAuth(14230): [SmsRetrieverHelper] Timed out waiting for SMS.

请帮助我更好地理解flatter async wait,或者告诉我哪里做错了,这样我就可以改进我的代码

共有1个答案

宦宏爽
2023-03-14

你使用的wait本身并不是错误的,但你的预期是错误的。

FirebaseAuth。例子verifyPhoneNumber将在执行该功能后完成其未来功能,但它不会等待短信发送。这里的未来表明,电话验证过程已经开始。换句话说,codeSent回调将在未来完成后的稍后时间调用(即,直到SMS发送给用户):

 /// [codeSent] Triggered when an SMS has been sent to the users phone, and
 ///   will include a [verificationId] and [forceResendingToken].

您需要在您的应用程序/小部件中说明这种行为。

以下是一种方法:

将函数定义更改为:

static Future<void> sendOtp({required String phoneNum, required PhoneCodeSent codeSent}) {
    String? vid;
    try {
      if (!kIsWeb) {
        await FirebaseAuth.instance.verifyPhoneNumber(
          phoneNumber: phoneNum,
          verificationCompleted: (PhoneAuthCredential credential) {},
          verificationFailed: (FirebaseAuthException e) {},
          timeout: const Duration(seconds: 5),
          codeSent: codeSent, // <~~ passed from your app
          codeAutoRetrievalTimeout: (String verificationId) {},
        );
      }
    // the rest is the same without return values tho
}

由于您编辑了上面的代码以在调用codeSent后让应用程序接收数据,因此您无需从sendOtp返回任何内容。

现在在您的小部件中:

onPressed:  () async {
    if (_textEditingController.text.isNotEmpty) {
      await Authentication.sendOtp(
        phoneNum: _textEditingController.text,
        codeSent: (String verificationId, int? resendToken) {
          // #2 Once this is called (which will be after the `print(a)` below),
          // update your app state based on the result (failed or succeeded)
        }
      );
      // #1 update your app state to indicate that the 'Message is on the way'
      // maybe show a progress indicator or a count down timer for resending
     // print(a);  <~~ there's no `a` anymore
    }
  };

正如您在上面看到的,代码#1将在代码#2之前执行,因为codeSent将在稍后的时间调用。我不确定是否有超时,或者你是否必须保留自己的计时器。

如果您不想在UI处理数据,您可以将回调更改为其他内容并使其像以前一样返回Map:

static Future<void> sendOtp({required String phoneNum, required ValueChanged<Map<String, dynamic>> onCodeSent}) {
    String? vid;
    try {
      if (!kIsWeb) {
        await FirebaseAuth.instance.verifyPhoneNumber(
          phoneNumber: phoneNum,
          verificationCompleted: (PhoneAuthCredential credential) {},
          verificationFailed: (FirebaseAuthException e) {},
          timeout: const Duration(seconds: 5),
          codeSent: (String verificationId, int? resendToken) {
            onCodeSent.call({'msg': verificationId, 'val': true});
          },
          codeAutoRetrievalTimeout: (String verificationId) {},
        );
      }
// the rest is the same without return values tho
}

在你的小部件上,你可以这样做:

onPressed:  () async {
    if (_textEditingController.text.isNotEmpty) {
      await Authentication.sendOtp(
        phoneNum: _textEditingController.text,
        codeSent: (Map<String, dynamic> map) {
          setState((){ 
             a = map
          });
        }
      );
 
    }
  };

这同样适用于web部分,只需使用映射调用回调:

final recaptchaVerifier = RecaptchaVerifier(
            container: null,
            size: RecaptchaVerifierSize.compact,
            theme: ThemeMode.system as RecaptchaVerifierTheme);
        await FirebaseAuth.instance
            .signInWithPhoneNumber(phoneNum, recaptchaVerifier)
            .then((confirmationResult) {
          onCodeSent.call({'vid': confirmationResult.verificationId, 'val': true);
        });
      }
 类似资料:
  • 在我的flatter应用程序中,我试图在异步函数完成后使用whenComplete()方法运行一些代码。问题是whenComplete()方法中的代码甚至在异步函数完成之前就被执行了。 我也尝试过使用then()方法,这也产生了相同的结果。 这是我在其中调用异步函数的init函数: 这是异步函数的函数体: 运行应用程序时的控制台输出为: 因此,在调用异步函数getUserHomes的init()函

  • 我有一个flutter应用程序,我在其中使用SQFLITE插件从SQLite DB中获取数据。这里我面临一个奇怪的问题。根据我的理解,我们使用async/wait或then()函数进行异步编程。这里我有一个db.query()方法,它执行一些SQL查询以从DB中获取数据。在这个函数获取数据后,我们在. then()函数中做一些进一步的处理。然而,在这种方法中,我遇到了一些问题。从我调用getExe

  • 问题内容: 建立: 我正在做一个ajax-jsonp调用,它工作正常。此的回调函数更改变量“ myVaraible”的值。在调用之后,有一些if-else逻辑对“ myVaraible”的值起作用。 这是代码: 问题: Ajax调用保持“待处理”状态,控制移至if- else块(有效执行myVariable的旧/陈旧值)。然后,ajax调用完成。简而言之,在两个方框中,先执行然后执行 如您所见,我

  • 我正在尝试为我的颤振应用程序编写一个测试。我为其编写测试的函数返回未来,因此我使用wait。 但是,只要使用任何WAIT语句,我就会得到MissingPluginException错误。 我尝试更改依赖项版本,但没有帮助。在GitHub上找不到与此相关的颤振问题或StackOverFlow。 预计工作正常。 获取错误: MissingPluginException(在channel plugins

  • 我试图在react/electron项目中使用async/await,但它不起作用。我想要的是获取docker容器状态列表。但是安慰。日志(列表)返回未定义的。 有人能帮我吗?:)

  • 我正在使用spring Roo并希望访问Controller类中的一个bean,该类在ApplicationContext.xml中具有以下配置: 配置类本身是: 在我的Controller中,我认为一个简单的Autowired注释应该可以完成这项工作 在启动过程中,spring在setSkipWeeks方法中打印消息。不幸的是,每当我在控制器中调用config.getSkipWeeks()时,它