停止在颤动中收听 Cloud Firestore 中的快照更新

Posted

技术标签:

【中文标题】停止在颤动中收听 Cloud Firestore 中的快照更新【英文标题】:Stop listening to snapshot updates in cloud firestore in flutter 【发布时间】:2019-01-25 20:00:48 【问题描述】:

我想停止收听快照更新。即使在屏幕关闭后,快照也会继续收听更新。我正在使用下面的代码来收听更新。

CollectionReference reference = Firestore.instance.collection('Events');
reference.snapshots().listen((querySnapshot) 
  querySnapshot.documentChanges.forEach((change) 
    // Do something with change
  );
)

【问题讨论】:

【参考方案1】:

您的侦听器是StreamSubscription 类型,因此您可以在侦听器上调用一些有用的方法,例如cancel()

    CollectionReference reference = Firestore.instance.collection('Events');
StreamSubscription<QuerySnapshot> streamSub = reference.snapshots().listen((querySnapshot) 
  querySnapshot.documentChanges.forEach((change) 
    // Do something with change
  );
);
//somewhere
streamSub.cancel();

【讨论】:

不仅在“某处”取消订阅,而且在不再需要它时,通常需要覆盖方法dispose(),如下所示:@override void dispose() if(streamSub!= null) streamSub.cancel(); super.dispose(); 那是完美的.. 但是如果您通过 StreamProvider 在 Ref 处获得更改怎么办?我将如何断开连接?还是我们无法处理?【参考方案2】:

listen 方法返回一个Subscription

该类用于取消监听。

您应该在您的状态中存储该对象以在处置时取消订阅。

【讨论】:

Remi - 我已经设置了stream.listen,但是当initState 加载屏幕时它正在侦听一次,并非总是在Firestore 上添加/更改某些内容时。请在***.com/questions/68052839/… 检查问题并建议我。非常感谢。 对如何使用 Riverpod 执行此操作有任何想法吗?现在坐了 4 天,无法取消听众。 Flutter 和 Firestore 都不会在导航时取消它们。【参考方案3】:

很晚的答案,但我想我会用代码示例完成以前的答案,因为它可能对其他人有用。

class EventsScreen extends StatefulWidget 
  EventsScreen(Key key) : super(key: key);

  @override
  _EventsScreenState createState() => _EventsScreenState();


class _EventsScreenState extends State<EventsScreen> 
  StreamSubscription<QuerySnapshot> _eventsSubscription;

  @override
  void initState() 
    // Initialise your stream subscription once
    CollectionReference eventsReference = Firestore.instance.collection('Events');
    _eventsSubscription = eventsReference.snapshots().listen((snapshot) => _onEventsSnapshot);
    super.initState();
  

  @override
  Widget build(BuildContext context) 
    // Build your widget here
    return Container();
  

  void _onEventsSnapshot(QuerySnapshot snapshot) 
    // Remove the setState() call if you don't want to refresh your screen whenever you get a fresh snapshot
    setState(() 
      snapshot?.documentChanges?.forEach(
        (docChange) => 
          // If you need to do something for each document change, do it here.
        ,
      );
      // Anything you might do every time you get a fresh snapshot can be done here.
    );
  

  @override
  void dispose() 
    // Cancel your subscription when the screen is disposed
    _eventsSubscription?.cancel();
    super.dispose();
  

这种方法利用 StatefulWidget 的状态来处理文档更改。

更好的方法是使用 Provider 或 BLoC pattern,这样就不会在 UI 中创建和处理对 Firestore 的订阅。

【讨论】:

很好的答案。我的问题是 - 如果我确实使用 Provider... 我将如何取消收听?至少在这里我有一个 subscription.cancel() 方法......知道吗?或者您不认为在不需要时持续收听会不必要地消耗资源吗? 解决了吗?我正在使用 redux 并且有 UI -> Thunk 中间件 -> 服务层。我的监听器在中间件层的方法调用中。如何调用一个操作来取消在不同方法中的订阅。 @JLP-Dev JLP-Dev,我已将listen 设置为Firestore snapshots(),但在调用listen 函数时遇到问题。您能否通过***.com/questions/68052839/…查看并建议我,非常感谢。 有没有人在如何使用 Riverpod/Provider 取消监听器方面取得进展?我就是做错了,已经有 4 天的压力了。听众根本不会被自己取消。【参考方案4】:

正确的方法是stream.pause() 所以监听器将处于暂停模式 cancel() 销毁监听器和他的内容

【讨论】:

【参考方案5】:

对我来说,我只是在快照方法上使用take。基本上,与 rxjs 与 Firebase 的原理相同。您获取一个数据流并停止收听。

return collection
        .withConverter<Discount>(
          fromFirestore: (snapshots, _) => Discount.fromMap(snapshots
              .data()!),
          toFirestore: (discount, _) => discount
              .toMap(),
        )
        .snapshots()
        .take(1); // Take 1 to stop listening to events

如果您运行并打印出 ConnectionState,您会看到它在获取集合中的所有文档后进入 Done

【讨论】:

以上是关于停止在颤动中收听 Cloud Firestore 中的快照更新的主要内容,如果未能解决你的问题,请参考以下文章

如何修复颤动的 cloud_firestore 依赖项?

如何使用 Cloud Firestore 在颤动中设置参考选择数组的位置条件 [关闭]

将 DateTime 序列化为时间戳以用于 Firestore 颤动

如何在颤动中收听 UIApplication 生命周期 iOS

Cloud Firestore 在流中等待未来 - 使用用户 ID 将用户加入文档

如何在颤动中显示来自firestore的特定文档详细信息