我正在开发一个Flutter应用程序,但想知道从UI调用异步代码时我该怎么办 - 让我们说一下UI小部件的构建方法。
例如,我的应用通过服务类连接Firebase,该服务类使用Async-Await样式从Firebase获取记录。使用await确保我的服务类的方法将在返回UI端之前完成记录检索。
但是,由于服务类的方法被标记为异步,因此在服务类的方法完成之前,它会立即向调用UI小部件返回Future,并且UI代码将继续运行。
是的我可以为“then()”回调编写代码来处理检索到的记录,但是后面的小部件中的其他代码又取决于异步调用的结果呢?这是否意味着我需要在“then()”子句中嵌入所有内容,并避免在返回Future的方法调用之后添加任何执行步骤?这种使用模式的任何建议模式?
@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
.....
.....
很抱歉,如果我的描述不明确,欢迎任何建议。
麦
答案 0 :(得分:20)
在Flutter中,有些小部件可以帮助您无缝地执行此操作(例如,FutureBuilder
,StreamBuilder
),您可以根据其分辨率控制要呈现的内容。
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
},);
}
StreamBuilder
的示例:
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
}
值得一提的是
如果您希望一次获取某些数据 并且无需一致连接或跟踪数据中的任何更改,则最好使用 FutureBuilder
。< / p>
另一方面,StreamBuilder
使您可以继续收听数据,并且可以根据数据中的任何更新来更新UI的状态。
答案 1 :(得分:1)
虽然我认为@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
,但这是另一种方法(即使它不一定是最佳做法)。