firebase Firestore:StreamBuilder如何工作以及如何有效地使用它

piztneat  于 2023-05-29  发布在  其他
关注(0)|答案(1)|浏览(132)

我想知道:
假设我在一个像Chat这样的应用程序中有一个streamBuilder,那么如果一个用户不在有streamBuilder的屏幕上,而添加了一个新的文档,它会自动算作阅读吗?
如何正确使用StreamBuilder,然后在用户离开屏幕时关闭它,以消耗最少的读取量。
谢谢你

06odsfpq

06odsfpq1#

根据定义:

StreamBuilder是一个基于数据流构建其输出的小部件。流可以是随时间发出数据的任何东西,例如Firestore集合。当流发出新数据时,StreamBuilder将重建其输出以反映新数据。
StreamBuilder接受两个参数:流和构建器函数。每当流发出新数据时,将调用构建器函数。
下面的代码显示了如何使用StreamBuilder显示Firestore文档列表:

class _HomePageState extends State<HomePage> {
  Stream<QuerySnapshot> stream; // Declaring Stream 

  @override
  void initState() {
    super.initState();

    stream = FirebaseFirestore.instance
        .collection('documents')
        .snapshots();
  }

  @override
  void dispose() {
// To close a StreamBuilder, you can use the dispose() method. 
    stream.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('StreamBuilder with Debounce and Throttle'),
      ),
      body: StreamBuilder<QuerySnapshot>(
        stream: stream,
        builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
         if (snapshot.hasError) return Text('Something went wrong');
        if (snapshot.connectionState == ConnectionState.waiting) return Text("Loading");
        List<DocumentSnapshot> documents = snapshot.data!.docs;
        return ListView.builder(
            itemCount: documents.length,
            itemBuilder: (BuildContext context, int index) {
              DocumentSnapshot document = documents[index];
              return ListTile(
                title: Text(document['title']),
                subtitle: Text(document['body']),
              );
            },
          );
        },
      ),
    );
  }
}
  • 向集合中添加新文档时,StreamBuilder将重新生成文档列表。这将算作从Firestore读取。
  • 但是当用户导航到新屏幕时,流将被释放。这是因为流只在页面处于视图中时侦听数据的更改。当您转到下一页时,流将不再侦听更改,并且您不会因任何读取而付费。
  • 如果您返回到最后一页,则将重新创建流,并且将向您收取读取以重建StreamBuilder的费用。因此,只有在需要显示随时间变化的数据(实时变化)时才使用StreamBuilder。如果您只需要显示静态数据,则可以使用ListViewFutureBuilder或其他不需要流的小部件。

TLDR:对你的应用程序做一些研究。你真的需要实时更新文档吗?如果你需要,那么小心地处理那些StreamBuilders,并确保在用户导航到新屏幕时处理掉那些流。

更新:当使用streamController时,我们还需要使用StreamSubscription.cancel()或调用streamController.cancel()来处理它,如下所示:

class _MyWidgetState extends State<MyWidget> {
  final StreamController<DocumentSnapshot> _streamController =
      StreamController.broadcast(); 

  StreamSubscription _subscription;

  @override
  void initState() {
    super.initState();

    // Listen to the stream and update the UI when a new document is added.
    _streamController.stream.listen((document) {
      setState(() {
        // Update the UI here.
      });
    },
    onDispose: () {
      // Dispose of the stream controller when the subscription is disposed.
      _streamController.dispose();
    });

  }

  @override
  void dispose() {
    // Dispose of the stream controller when the widget is disposed.
    _streamController.dispose(); // when used just StreamController
    _subscription.cancel(); // when used StreamSubscription 
    super.dispose();
  }
}

参考文献:
1.一次性读取
1.实时变化

  1. StreamBuilder class

相关问题