颤振:从UI调用异步代码的最佳实践

时间:2018-03-06 16:28:04

标签: async-await dart flutter

我正在开发一个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
    .....
    .....

很抱歉,如果我的描述不明确,欢迎任何建议。

2 个答案:

答案 0 :(得分:20)

在Flutter中,有些小部件可以帮助您无缝地执行此操作(例如,FutureBuilderStreamBuilder),您可以根据其分辨率控制要呈现的内容。

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,但这是另一种方法(即使它不一定是最佳做法)。