【问题标题】:How check the ConnectionState of Firestore snapshot stream with StreamProvider?如何使用 StreamProvider 检查 Firestore 快照流的 ConnectionState?
【发布时间】:2020-08-08 20:03:46
【问题描述】:

cloud_firestore 文档中的此示例使用 StreamBuilderAsyncSnapshotConnectionState 来处理处于不同状态的流。当通过StreamProvider 而不是StreamBuilder 访问流时,是否有类似的方法来管理ConnectionState?什么是避免它在短时间内返回 null 直到它实际上有来自 Firestore 的文档的最佳方法?

这里是 cloud_firestore 文档中带有 StreamBuilder 的示例:

    class BookList extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return StreamBuilder<QuerySnapshot>(
          stream: Firestore.instance.collection('books').snapshots(),
          builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
            if (snapshot.hasError)
              return new Text('Error: ${snapshot.error}');
            switch (snapshot.connectionState) {
              case ConnectionState.waiting: return new Text('Loading...');
              default:
                return new ListView(
                  children: snapshot.data.documents.map((DocumentSnapshot document) {
                    return new ListTile(
                      title: new Text(document['title']),
                      subtitle: new Text(document['author']),
                    );
                  }).toList(),
                );
            }
          },
        );
      }
    }

我有一个相当基本的流:

    List<AuditMark> _auditMarksFromSnapshot(QuerySnapshot qs) {
      return qs.documents.map((DocumentSnapshot ds) {
        return AuditMark.fromSnapshot(ds);
      }).toList();
    }

    Stream<List<AuditMark>> get auditMarks {
      return Firestore.instance
          .collection('_auditMarks')
          .snapshots()
          .map(_auditMarksFromSnapshot);
    }

这是通过StreamProvider 访问的(此处省略了其他提供者):

    void main() async {
      runApp(MultiProvider(
        providers: [
          StreamProvider<List<AuditMark>>(
              create: (_) => DatabaseService().auditMarks, ),
        ],
        child: MyApp(),
      ));
    }

我尝试以某种方式将QuerySnapshot 转换为AsyncSnapshot&lt;QuerySnapshot&gt;,但可能弄错了。 当然可以像这样给StreamProvider 一些initialData - 但这很麻烦,容易出错并且可能很昂贵:

    initialData: <AuditMark>[
      AuditMark.fromSnapshot(await Firestore.instance
          .collection('_auditMarks')
          .orderBy('value')
          .getDocuments()
          .then((value) => value.documents.first))

...但我希望有一种更智能的方法来管理连接状态并避免它在发出文档之前返回 null?

【问题讨论】:

    标签: flutter dart google-cloud-firestore flutter-provider


    【解决方案1】:

    我一直在处理这个问题,不想声明initialData 来绕过这个问题。

    我所做的是创建一个 StreamBuilder 作为 StreamProvider 的 。 这样我就可以在 StreamProvider 中使用 StreamBuilder 的 snapshot.connectionState 属性。

    代码如下:

        return StreamProvider<List<AuditMark>>.value(
            value: DatabaseService().auditMarks,
            child: StreamBuilder<List<AuditMark>>(
                    stream: DatabaseService().auditMarks,
                    builder: (context, snapshot) {
                        if (!snapshot.hasError) {
                            switch (snapshot.connectionState) {
                                case ConnectionState.none: // if no connection
                                    return new Text(
                                        "Offline!",
                                        style: TextStyle(fontSize: 24, color: Colors.red),
                                        textAlign: TextAlign.center,
                                    );
                                case ConnectionState.waiting
                                    // while waiting the data, this is where you'll avoid NULL
                                    return Center(child: CircularProgressIndicator());
                                default:
                                    return ListView.builder(
                                        // in my case I was getting NULL for itemCount
                                        itemCount: logs.length,
                                        itemBuilder: (context, index) {
                                            return LogsTile(log: logs[index]);
                                        },
                                    );
                            }
                        }
                        else {
                            return new Text(
                                "Error: ${snapshot.error}",
                                style: TextStyle(fontSize: 17, color: Colors.red),
                                textAlign: TextAlign.center,
                            );
                        }
                    }
            )
        );
    

    【讨论】:

    • 不错的解决方法。在我的情况下,我不得不使用多个嵌套的 StreamBuilder,因为我依赖于多个 StreamProvider,因此更喜欢下面的方法。
    【解决方案2】:

    可能不是最优雅的解决方案,但我最终使用了一个简单的 bool 变量,虽然并非所有 StreamProviders 都发出了值,但该变量是正确的。

    bool _waitForStreams = false;
    if (Provider.of<List<AuditMark>>(context) == null) _waitForStreams = true;
    if (Provider.of<...>>(context) == null) _waitForStreams = true; 
    (etc. repeat for every StreamProvider)
    
    // show "loading..." message while not all StreamProviders have supplied values
    if (_waitForStreams) {
      return Scaffold(
        appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  CircularProgressIndicator(),
                  SizedBox(height: 25.0),
                  Text('loading...'),
                ],
              )
            ],
          ),
        );
    }
    

    【讨论】:

      【解决方案3】:

      我不知道它是否正确,但这是我实现它的方式。

      由于streamProviser不提供连接状态,我先用streamBuilderprovider.value分发数据:

      return StreamBuilder<BusinessM>(
          stream: db.businessDetails(), //firebase stream mapped to business model class
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.active)
              return Provider<BusinessM>.value(
                value: snapshot.data,
                child: Businesspage(),
              );
            else
              return Center(child: CircularProgressIndicator());
          });
      

      【讨论】:

        猜你喜欢
        • 2020-09-26
        • 1970-01-01
        • 2021-06-17
        • 1970-01-01
        • 2018-06-11
        • 1970-01-01
        • 2021-11-24
        • 2020-07-24
        • 2021-09-02
        相关资源
        最近更新 更多