firebase Flutter Firestore -侦听数据流时捕获异常

oipij1gg  于 2022-12-14  发布在  Flutter
关注(0)|答案(4)|浏览(141)

当使用get()方法从Firestore中获取所有文档时,默认情况下,如果没有互联网连接,它不会抛出异常。相反,它会查找该高速缓存并返回缓存的数据。但有时候你需要知道一个集合当前是否为空或者你只是无法连接到数据库。
对于获取数据,有一个解决方案:可以将GetOptions参数设置为Source.server。这样,如果无法访问服务器,则会引发错误。
现在,我正在为snapshots()方法寻找一个与此选项等效的选项,它返回一个Stream,而不仅仅是单个数据。
因此:

await _firestore
        .collection('stuff')
        .where("someBool", isEqualTo: false)
        .get(const GetOptions(source: Source.server));

将在错误连接上引发FirebaseException,而:

_firestore
    .collection('stuff')
    .where("someBool", isEqualTo: false)
    .snapshots()
    .listen((snap) { ...  }, onError: (e) {
         //never called...
         debugPrint(e.toString());
     });

在这个例子中我就是找不到答案。
我得到的最接近的解决方案是检查snap.metadata.isFromCache并在值为true时抛出异常。但这并不可靠。False意味着快照保证与服务器保持最新。但在某些情况下,即使它从服务器得到了有效的响应,它也是true
编辑:如果我在本地而不是直接在查询中过滤someBoolisFromCache属性将是一个解决方案。

_firestore
    .collection('stuff')
    .where("someBool", isEqualTo: false)
    .snapshots(includeMetadataChanges: true)
    .listen((snap) { 
         //`hasPendingWrites` is false in all these cases:
         //  1. changing a document's `someBool` field from `false` to `true` and vise versa
         //  2. requesting with server connection
         //  3. requesting without server connection
         debugPrint("snap metadata pendingWrites is: ${snap.metadata.hasPendingWrites}");
         if (snap.metadata.isFromCache) {
         //I thought data from cache is only used when there's trouble connecting to the server which is not the case:
         //
         //no internet connection will indeed cause this value to be true
         //but changing a document's `someBool` field from `false` to `true` however, will  cause it to be true, too
             debugPrint("metadata of this snap is from cache -> throwing NoInternetException");
             throw NoInternetException();
         }
     }, onError: (e) {
         //never called...
         debugPrint(e.toString());
     });

编辑:我已禁用脱机持久性:

db.settings = const Settings(persistenceEnabled: false);

实验:更新文档的someBool域(直接从Firestore Console):

  • 使用互联网:*

对错:14n1x是15n1x,16n1x是17n1x
假到真:pendingWritesfalseisFromCachetrue
在收听Stream时关闭互联网:
第一个是第一个
因此,互联网的“假对真”情况导致使用isFromCache成员的误报。
编辑:
该文件规定:
如果调用[DocumentReference.snapshots]或[Query.snapshots]时将includeMetadataChanges参数设置为true,则一旦客户端从后端接收到最新数据,就会收到另一个isFomCache等于false的快照。
现在,在此误报情况下(将bool从false设置为true),Stream触发两次:

  • 首次使用isFromCache:x1米36英寸1x
  • 第二次(第一次后立即):isFromCache:x1米38英寸

因此,由于某种原因,即使有到服务器的连接,Firestore也会该高速缓存中读取。

zf9nrax1

zf9nrax11#

即使您的应用暂时失去网络连接,Firebase应用也能正常工作。此外,Firebase提供了用于在本地持久化数据、管理在线状态和处理延迟的工具。
例如,您可以检查Internet连接,如检测连接状态

final connectedRef = FirebaseDatabase.instance.ref(".info/connected");
connectedRef.onValue.listen((event) {
  final connected = event.snapshot.value as bool? ?? false;
  if (connected) {
    debugPrint("Connected.");
  } else {
    debugPrint("Not connected.");
  }
});

有关更多详细信息,您可以查看以下链接:-https://firebase.google.com/docs/database/flutter/offline-capabilities
特别是消防仓库,你可以遵循这个

db
    .collection('stuff')
    .where("someBool", isEqualTo: false)
    .snapshots(includeMetadataChanges: true)
    .listen((querySnapshot) {
  for (var change in querySnapshot.docChanges) {
    if (change.type == DocumentChangeType.added) {
      final source =
          (querySnapshot.metadata.isFromCache) ? "local cache" : "server";

      print("Data fetched from $source}");
    }
  }
});

有关更多详细信息,请访问以下链接(用于Firestore):-https://firebase.google.com/docs/firestore/manage-data/enable-offline#dart_2

bvjveswy

bvjveswy2#

为了做你想做的事,你必须:首先确保已禁用并清除缓存:

FirebaseFirestore.instance.settings =
    Settings(persistenceEnabled: false);

await FirebaseFirestore.instance.clearPersistence();

现在,当你尝试在没有网络连接的情况下访问任何东西时,你应该得到一个“isFromCache”等于true的空快照。不幸的是,在这种情况下没有错误。这只是它的设计方式。
希望我能帮上忙。

vu8f3i0k

vu8f3i0k3#

您所描述的行为正是Firestore开发人员所希望的,而且它确实有其缺点。
我唯一要添加到您当前解决方案中的是使用connectivity_plusinternet_connection_checker之类的方法进行连接检查

final _hasConnection = await yourConnectivityProvider.isConnected();

_firestore
    .collection('stuff')
    .where("someBool", isEqualTo: false)
    .snapshots(includeMetadataChanges: true)
    .listen((snap) { 
         //`hasPendingWrites` is false in all these cases:
         //  1. changing a document's `someBool` field from `false` to `true` and vise versa
         //  2. requesting with server connection
         //  3. requesting without server connection
         debugPrint("snap metadata pendingWrites is: ${snap.metadata.hasPendingWrites}");
         if (snap.metadata.isFromCache) {
         //I thought data from cache is only used when there's trouble connecting to the server which is not the case:
         //
         //no internet connection will indeed cause this value to be true
         //but changing a document's `someBool` field from `false` to `true` however, will  cause it to be true, too
             if (!_hasConnection) {
                 debugPrint("metadata of this snap is from cache -> throwing NoInternetException");
                 throw NoInternetException();
              }
         }
     }, onError: (e) {
         //never called...
         debugPrint(e.toString());
     });

connectivity_plus只会检测设备是否开启了Wifi/4G,但它非常轻,不会影响电池。
internet_connection_checker将为您提供有关连接的“真实的”信息,但它必须查询服务器才能获得此信息。

它会100%正常工作吗?可能不会。
在一些用例中,即使有这种“安全性”,您也可能得到误报(甚至是假阴性,这是最糟糕的)。

agyaoht7

agyaoht74#

看到我的票我在六月打开:https://github.com/firebase/flutterfire/issues/8961
正如您在最后一个条目中看到的,我在Firebase支持处打开了一个功能请求,要求在Query.snapshots和DocReference.snaphots调用中添加GetOptions参数。
此外,您还可以查看Nimbostratus包,它试图克服Firestore中的当前限制。

相关问题