Async await 颤振:从UI调用异步代码的最佳实践
我正在开发一个flatter应用程序,但不知道从UI调用异步代码时应该做什么——比如说UI小部件的构建方法 例如,我的应用程序通过服务类连接Firebase,该服务类使用异步等待样式从Firebase获取记录。使用wait可以确保我的服务类的方法在返回UI端之前完成记录检索 但是,由于服务类的方法被标记为async,因此在服务类的方法完成之前,它会立即将未来返回给调用的UI小部件,并且UI代码保持运行 是的,我可以为“then()”回调编写代码来处理检索到的记录,但是接下来的小部件中的其他代码如何,取决于异步调用的结果?这是否意味着我需要将所有内容嵌入到“then()”子句中,并避免在返回未来的方法调用之后添加任何执行步骤?对于这种使用模式有什么建议吗Async await 颤振:从UI调用异步代码的最佳实践,async-await,dart,flutter,Async Await,Dart,Flutter,我正在开发一个flatter应用程序,但不知道从UI调用异步代码时应该做什么——比如说UI小部件的构建方法 例如,我的应用程序通过服务类连接Firebase,该服务类使用异步等待样式从Firebase获取记录。使用wait可以确保我的服务类的方法在返回UI端之前完成记录检索 但是,由于服务类的方法被标记为async,因此在服务类的方法完成之前,它会立即将未来返回给调用的UI小部件,并且UI代码保持运行 是的,我可以为“then()”回调编写代码来处理检索到的记录,但是接下来的小部件中的其他代码如
@override
Widget build(BuildContext context) {
RealtimeDatabase.getData() // my service class
.then((onValue) {
..... // do something after the async call is completed
}
..... // do something immediately before the async call is done
class RealtimeDatabase {
Future<String> getData() async {
DataSnapshot dataSnapshot = await FirebaseDatabase.instance.reference().orderByKey().once(); // will wait until completed
.....
.....
@覆盖
小部件构建(构建上下文){
RealtimeDatabase.getData()//我的服务类
.然后((onValue){
..…//在异步调用完成后执行某些操作
}
..…//在异步调用完成之前立即执行某些操作
类实时数据库{
Future getData()异步{
DataSnapshot DataSnapshot=等待FirebaseDatabase.instance.reference().orderByKey().once();//将等待完成
.....
.....
对不起,如果我在这里的描述不够清晰,欢迎任何建议
Jimmy在Flatter中,有一些小部件可以帮助您无缝地执行此操作(例如,,),并且您可以根据它们的分辨率控制要渲染的内容
FutureBuilder
上的示例:
Widget build(BuildContext context) {
return new FutureBuilder(
future: FirebaseDatabase.instance.reference().child("node"),
builder: (BuildContext context, AsyncSnapshot snapshot) {
return snapshot.hasData? new Scaffold(
///start building your widget tree
):new CircularProgressIndicator(); ///load until snapshot.hasData resolves to true
},);
}
class Database {
DatabaseReference _refProfile = FirebaseDatabase.instance.reference().child(
"profiles");
getProfiles() => _refProfile.onValue; }
StreamBuilder
示例:
Widget build(BuildContext context) {
return new FutureBuilder(
future: FirebaseDatabase.instance.reference().child("node"),
builder: (BuildContext context, AsyncSnapshot snapshot) {
return snapshot.hasData? new Scaffold(
///start building your widget tree
):new CircularProgressIndicator(); ///load until snapshot.hasData resolves to true
},);
}
class Database {
DatabaseReference _refProfile = FirebaseDatabase.instance.reference().child(
"profiles");
getProfiles() => _refProfile.onValue; }
Widget build(BuildContext context) {
return new StreamBuilder<Event>(
stream: _database.getProfiles(), //_database = new Database()
builder: (BuildContext context, AsyncSnapshot<Event> event) {
return event.hasData?new Scaffold(
///build your widget tree
):new CircularProgressIndicator();
/// place holder
}
小部件构建(构建上下文){
返回新的StreamBuilder(
流:_database.getProfiles(),//_database=new database()
生成器:(BuildContext上下文,异步快照事件){
返回事件.hasData?新脚手架(
///构建小部件树
):新的循环压缩机指示器();
///占位符
}
值得一提的是
FutureBuilder
在您希望一次获取某些数据,而不关心保持一致连接或跟踪数据中的任何更改时,最好使用
另一方面,
StreamBuilder
使您能够持续监听数据,并且您可以根据数据中的任何更新更新UI的状态。虽然我认为@aziza提到的方法肯定是可行的,但值得注意的是,您也可以“自己滚动”
例如,在initState()
中,您可以执行以下操作:
@override
void initState() {
super.initState();
_myItems = // some sane default
FirebaseDatabase.instance.reference().child("node")
.then((items) {
if (widget.mounted) setState(() { _myItems = items; }
});
}
Widget build(BuildContext context) {
return new Scaffold(
///start building your widget tree
);
}
最好在这里使用
FutureBuilder
,但这是另一种方法(即使这不一定是最佳实践)tion。非常感谢,我已经挣扎了几天,不知道Flitter有这么好的功能!似乎一个返回语句缺少StreamBuilder示例。我想知道的是“构建您的小部件树”的位置发生了什么注释。例如,如何在ListView中显示流配置文件生成的内容…@Wonderjimmy这是我的错,我应该更清楚,你永远不会想在脚手架级别上执行FutureBuilder,而是在body属性中执行。这样,你的appbar、drawer、FAB、tabs…等将正常加载,并且仅在正文中加载content将加载。嗨,Dan,在您的解决方案中,构建方法是否被调用两次?一次是在_myItems为null时,第二次是在调用setState之后?但是在重建期间,是否会再次调用initState?initState仅在第一次将小部件添加到树中时才会被调用。但是,是的,在本例中,构建将被调用两次,一次是在状态的初始化,在将来解析之后。initState是不可取的,因为当您回到旧屏幕时,有时我们需要调用API,为此,FutureBuilder是最好的方法。