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

use*_*856 5 firebase flutter google-cloud-firestore

当使用该方法获取集合的所有文档时,默认情况下,如果没有互联网连接,它不会抛出异常。相反,它查找缓存并返回缓存的数据。但有时您需要知道集合当前是否实际上为空Firestoreget()您只是无法连接到数据库。

对于仅获取数据,有一个解决方案:GetOptions可以将参数设置为Source.server。这样,如果无法访问服务器,就会抛出错误。

现在我正在寻找与此选项等效的方法,该snapshots()方法返回 aStream而不仅仅是单个数据。所以我需要流在无法连接到服务器时发出错误。

所以:

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

将抛出一个FirebaseException错误连接,同时:

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

在这个例子中我就是找不到。

我得到的最接近的解决方案是检查snap.metadata.isFromCache并在值为 时抛出异常true。但这并不可靠。False 表示保证快照与服务器保持同步。但在某些情况下,true即使它从服务器获得了有效响应也是如此。

编辑:如果我在本地过滤而不是直接在查询中isFromCache过滤,属性将是一个解决方案。someBool

_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());
     });
Run Code Online (Sandbox Code Playgroud)

编辑:我禁用了离线持久性:

db.settings = const Settings(persistenceEnabled: false);
Run Code Online (Sandbox Code Playgroud)

实验:更新文档的someBool字段(直接来自Firestore Console):

有互联网:

true 到 false: pendingWritesfalse, isFromCachefalse

假到真: pendingWritesfalse, isFromCachetrue

Stream当正在收听时关闭互联网时:

pendingWrites伊斯兰falseisFromCachetrue

因此,互联网上的“假对真”案例会导致使用该会员的误报isFromCache

编辑:

文档指出:

如果您调用 [DocumentReference.snapshots] 或 [Query.snapshots] 并将 includeMetadataChanges参数设置为,一旦客户端从后端收到最新数据,true您将收到另一个快照。isFomCachefalse

现在,在这种误报情况下(将布尔值设置为falseto true),Stream会触发两次:

  • 第一次与isFromCachetrue
  • 第二次(紧接第一次之后):isFromCache:false

因此,由于某种原因,即使存在与服务器的连接,Firestore 也会从缓存中读取数据。所以在投掷时我不能依赖这个属性NoInternetException

shi*_*kla 3

即使您的应用暂时失去网络连接,Firebase 应用程序也能正常运行。此外,Firebase 还提供了用于在本地保存数据、管理状态和处理延迟的工具。

例如,您可以像这样检查互联网连接, 检测连接状态

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.");
  }
});
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,您可以查看此链接:- https://firebase.google.com/docs/database/flutter/offline-capability

对于特别是 firestore 你可以遵循这个,

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}");
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请点击此链接(对于 firestore):- https://firebase.google.com/docs/firestore/manage-data/enable-offline#dart_2