自從我開始 Flutter 以來,我面臨著一個與 Flutter async-await 相關的問題。大多數情況下,我嘗試使用 Future 并等待結果,它會跳過等待并獲得最短的回傳方式。
if i try to print after await the null value prints first and then await is called
here is my onPressed
onPressed: () async {
if (_textEditingController.text.isNotEmpty) {
Map a = await Authentication.sendOtp(
phoneNum: _textEditingController.text);
print(a);
}
},
and my Authentication class:
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};
}
}
}
output i get:
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.
請幫助更好地理解 flutter async-await,或者告訴我哪里做錯了,以便我可以改進我的代碼
uj5u.com熱心網友回復:
您await本身并沒有使用錯誤,而是您有錯誤的期望。
FirebaseAuth.instance.verifyPhoneNumber一旦函式被執行,它將完成它的未來,但它不會等到發送短信。這里的 Future 表示手機驗證的程序已經開始。換句話說,codeSent回呼將在 Future 完成后的稍后時間呼叫(即直到 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);
});
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/388357.html
上一篇:將超時插入代碼但它不會創建暫停
