在 Flutter 应用程序中使用 Firestore 中的离线持久性

Posted

技术标签:

【中文标题】在 Flutter 应用程序中使用 Firestore 中的离线持久性【英文标题】:Using Offline Persistence in Firestore in a Flutter App 【发布时间】:2019-05-02 03:37:30 【问题描述】:

我正在开发一个使用 Firebase 的 Firestore 将数据发送到网络的应用。该应用程序的功能之一是能够在离线时将数据保存在设备中,并在互联网连接恢复时将其发送到 Firestore。 我激活了离线持久性,但它不起作用。

调试控制台:

W/OkHttpClientTransport(28536): Failed closing connection
W/OkHttpClientTransport(28536): javax.net.ssl.SSLException: Write error: ssl=0x7f7acfc408: I/O error during system call, Broken pipe
W/OkHttpClientTransport(28536):     at com.google.android.gms.org.conscrypt.NativeCrypto.SSL_write(Native Method)
W/OkHttpClientTransport(28536):     at com.google.android.gms.org.conscrypt.NativeSsl.write(:com.google.android.gms@14798020@14.7.98 (040406-222931072):4)

如何在互联网恢复时激活离线持久性并与 Firestore 同步?

我的密码:

Future<Null> sendFirebaseData(var selectedModel) async 

    Firestore.instance.enablePersistence(true);
    var certID = await getIDCertificado();

    var dateTime = new DateTime.now();
    var nowHour = new DateFormat('kk:mm:ss').format(dateTime);

      Map<String, dynamic> dataHeader = 
        'ID':                certID,
        ;

      Map<String, dynamic> finalDataMap = ..addAll(dataGeneral)
                                          ..addAll(dataInstrumento)..addAll(dataPadrao)
                                          ..addAll(dataAdicional)..addAll(dataHeader);

      await Firestore.instance.collection('certificados').document((certID.toString()))
          .setData(finalDataMap);

【问题讨论】:

请注意“Firestore.instance.enablePersistence(true);”现在已弃用。您应该调用“Firestore.instance.settings(persistenceEnabled: true);”而是。 【参考方案1】:

当您在 Firestore 中使用离线持久性时,请勿使用 Transactions 或 await 进行响应。

所以,改变这个:

  await Firestore.instance.collection('certificados').document((certID.toString()))
      .setData(finalDataMap);

到这里:

 Firestore.instance.collection('certificados').document((certID.toString()))
      .setData(finalDataMap);

当您恢复互联网连接时,即使您在后台,您的数据也会自动同步。

在您的应用关闭时不起作用。

离线时的承诺和回调上下文

为什么上述代码更改以删除“等待”有效。

Reference: Firebase Video - How Do I Enable Offline Support 11:13

在服务器上的文档写入成功之前,不会调用您的回调并且您的承诺不会完成。这就是为什么如果您的 UI 等到写入完成才执行某项操作,即使实际写入本地缓存,它也会在“离线模式”下冻结。

可以不使用async / await.then()callbacks。 Firestore 将始终像立即应用数据更改一样“采取行动”,因此您无需等待处理新数据。

仅当您需要确保服务器写入已经发生并且您希望在获得确认之前阻止其他事情发生时,您才需要使用回调和承诺。

【讨论】:

谢谢! Flutter web 上的等效版本是什么? 谢谢!当我删除 await 关键字时它起作用了:) 这个答案太棒了为什么 Flutter firestore 文档没有明确包含此信息。 但是如果我需要等待才能访问 DocumentSnapshot 的 ID,我该怎么办? .then() 回调函数还能离线使用吗?【参考方案2】:

我认为当前的答案已经过时了。根据firebase documentation,Android 和 ios 默认启用离线持久性。对于网络,它不是。

在 Flutter 中,firestore 的实现是基于底层操作系统的。所以你在移动应用上是安全的,但在 web 上却不是 Flutter。

【讨论】:

不,答案已更新。我只是尝试不使用 await 关键字并且它有效。它没有使用带有 await 关键字的离线数据库。【参考方案3】:

默认启用,但仍然仅在您不使用 await 或 transactions 时启用,此外,您可以使用 timeout 停止在特定时间后通过 firestore 监听网络连接。

 ref.setData(newNote.toMap()).timeout(Duration(seconds: 2),onTimeout:() 

        //cancel this call here

        print("do something now");
      );

【讨论】:

以上是关于在 Flutter 应用程序中使用 Firestore 中的离线持久性的主要内容,如果未能解决你的问题,请参考以下文章

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

从 Firebase 异步加载数据

从Firebase本地实时存储Room DB上的数据

冻结的 Json 序列化程序 - Firestore 通信

Flutter-如何在flutter的整个应用程序生命周期中将数据保存在内存中?

Flutter:在 web 、android 和 ios 中使用相同的应用程序