【问题标题】:How do I wait for an async function to finish executing before rendering a widget in Flutter如何在 Flutter 中渲染小部件之前等待异步函数完成执行
【发布时间】:2019-11-06 11:01:14
【问题描述】:
在我的 main.dart 文件中,我想检查用户是否已登录,以便将他引导到相应的屏幕。我正在使用 SharedPrefence 从 Firebase 存储用户详细信息。
如何告诉我的函数等到我的 SharedPreference 异步函数完成执行才能呈现适当的小部件。
下面是我的代码
Widget _gotoHomeScreen() {
AuthService.getuserPrefEmail().then((email) {
print(email);
AuthService.email = email;
if (email == null) {
return LoginScreen();
} else {
AuthService.uid = email;
return HomeMenuScreen();
}
});
}
【问题讨论】:
标签:
firebase
flutter
dart
async-await
【解决方案1】:
您不必等待构建,您应该构建一些东西,向用户显示应用正在加载某些东西(或空白屏幕),然后在功能结束时重建。
您可以在创建小部件时将 Widget 变量设置为默认值,例如使用 CircularProgressIndicator,然后使用 setState 更改它,如下所示:
class YourWidgetState extends State<YourWidget> {
Widget _body = CircularProgressIndicator(); // Default Body
@override
void initState(){
_gotoHomeScreen();
}
@override
Widget build(BuildContext context){
return _body;
}
Widget _gotoHomeScreen() {
AuthService.getuserPrefEmail().then((email){
AuthService.email = email;
if (email == null) {
setState(() => _body = LoginScreen());
} else {
AuthService.uid = email;
setState(() => _body = HomeMenuScreen());
}
});
}
}
另一种方法是使用变量通知您加载情况,例如bool finishedLoading,并在加载完成后调用setState 更改值,使用email 变量您设置知道用户何时登录,并进行有条件的构建,如下所示:
bool loading = true;
@override
Widget build(BuildContext context){
if(loading) return CircularProgressIndicator();
if(AuthService.email == null)
return LoginScreen();
else
return HomeMenuScreen();
}
Widget _gotoHomeScreen() {
AuthService.getuserPrefEmail().then((email){
AuthService.email = email;
if (email != null) {
AuthService.uid = email;
}
setState((){ loading = false; });
});
}
【解决方案2】:
使用简单的 FutureBuilder!
https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
FutureBuilder<Email>(
future: AuthService.getuserPrefEmail(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.active:
case ConnectionState.waiting:
return CircularProgressIndicator();
case ConnectionState.done:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
.... here route to your screen or set it how you want
}
},
)