无法在 Firestore 中禁用离线数据

Posted

技术标签:

【中文标题】无法在 Firestore 中禁用离线数据【英文标题】:Can't Disable Offline Data In Firestore 【发布时间】:2018-04-04 06:46:50 【问题描述】:

从我的Firestore Database 删除数据后,我的android app 需要一些时间才能意识到数据已被删除,我认为这是由于自动数据缓存而发生的。我的应用与离线使用无关,我想禁用此功能...

我已经在我的自定义Application Class中添加了这个:

import android.app.Application;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.FirebaseFirestoreSettings;

public class ApplicationClass extends Application 

    @Override
    public void onCreate() 
        super.onCreate();

        FirebaseFirestore db=FirebaseFirestore.getInstance();
        FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
                .setPersistenceEnabled(false)
                .build();
        db.setFirestoreSettings(settings);
    

问题是在关闭互联网连接后重新打开(在应用程序仍在运行时,无论是否在后台)-Firestore module 似乎失去了与服务器,它会执行与预期操作相反的操作 - 不是停止从缓存中获取数据,而是只从缓存中获取数据

例如,调试此代码将始终显示 isFromCachetrue 并且 documentSnapshot 为空(即使在 server 一侧- 它不是空的):

usersRef.document(loggedEmail).collection("challenges_received").get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() 
    @Override
    public void onSuccess(QuerySnapshot documentSnapshots) 
        boolean isFromCache=documentSnapshots.getMetadata().isFromCache();
        if (!documentSnapshots.isEmpty()) 
        
    
);

这是正常行为吗?

还有其他方法可以禁用Cloud Firestore 中的数据缓存吗?


编辑:

在自定义 Application Class 中添加:FirebaseFirestore.setLoggingEnabled(flase);(而不是上面的代码)会得到相同的结果。

【问题讨论】:

mDatabase.getReference().keepSynced(false); FirebaseDatabase.getInstance().setPersistenceEnabled(false); 个人看我不认为它与缓存有任何关系,如果它有这个问题然后检查启用离线持久性(firebase.google.com/docs/firestore/manage-data/…) 请考虑放宽这里的小修改。这个问题已经有一个赏金集,所以它会再展示 5 天,而你不需要修改它。 你试过了吗:***.com/questions/46790741/… @AlexanderVitanov 如果我找不到解决方案,这似乎是一个可以考虑的选项。但是,如果我检查了快照是否来自缓存并且我发现它确实如此,我是否能够从服务器获取快照?我可以选择吗? 【参考方案1】:
// Enable Firestore logging
    FirebaseFirestore.setLoggingEnabled(flase);
// Firestore
    mFirestore = FirebaseFirestore.getInstance();

一般来说:Firebase 客户端会尽量减少下载数据的次数。但它也尽量减少它使用的内存/磁盘空间量。

确切的行为取决于许多因素,例如另一个侦听器是否在该位置保持活动状态以及您是否使用磁盘持久性。如果您有两个相同(或重叠)数据的侦听器,则更新只会下载一次。但是,如果您删除某个位置的最后一个侦听器,则该位置的数据将从(内存和/或磁盘)缓存中删除。

没有看到完整的代码,很难判断你的情况会发生什么。

或者:您可以通过启用 Firebase 的日志记录 [Firebase setLoggingEnabled:YES] 自行检查;

试试这个 For FireBase 数据库

  mDatabase.getReference().keepSynced(false);      
      FirebaseDatabase.getInstance().setPersistenceEnabled(false);

【讨论】:

感谢您的回答。如果我输入FirebaseFirestore.setLoggingEnabled(false) 而不是setPersistenceEnabled(false),结果保持不变,我不能在离线后向服务器发出任何请求,而不是重新在线......关于你在“试试这个”下写的东西,我认为是给Realtime Database,而不是Firestore 会再次审核【参考方案2】:

我刚刚在一个 Android 应用程序中运行了一些测试,看看它是如何工作的。由于 Firestore 目前仍在beta release 中,并且产品可能随时发生变化,我不能保证这种行为将来仍然存在。

db.collection("tests").document("fOpCiqmUjAzjnZimjd5c").get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() 
    @Override
    public void onComplete(@NonNull Task<DocumentSnapshot> task) 
        DocumentSnapshot documentSnapshot = task.getResult();
        System.out.println("isFromCache: " + documentSnapshot.getMetadata().isFromCache());
    
);

关于代码,无论我们是从缓存中获取数据还是您连接到服务器,都是一样的。

当我在线时,它会打印:

isFromCache: false

当我离线时,它会打印:

isFromCache: true

因此,目前,当您未连接到服务器时,无法停止从缓存中检索数据,因为您无法在连接到服务器时强制从缓存中检索数据服务器。

如果我使用监听器:

db.collection("tests").document("fOpCiqmUjAzjnZimjd5c").addSnapshotListener(new DocumentListenOptions().includeMetadataChanges(), new EventListener<DocumentSnapshot>() 
    @Override
    public void onEvent(DocumentSnapshot documentSnapshot, FirebaseFirestoreException e) 
        System.out.println("listener.isFromCache: " + documentSnapshot.getMetadata().isFromCache());
    
);

我在线时会打印两张照片:

listener.isFromCache: true
listener.isFromCache: false

Firestore 旨在在设备永久离线或您的应用程序暂时失去其网络连接且暂时无法更改此行为时从缓存中检索数据。

作为脑震荡,执行此类操作的 API 目前还不存在。

编辑:与在 Firebase 中不同,您需要使用以下代码行来启用离线持久性:

FirebaseDatabase.getInstance().setPersistenceEnabled(true);

在 Firestore 中,对于 Android 和 ios,离线持久性为 enabled by default

使用上述代码行意味着您告诉 Firebase 创建数据库的本地(内部)副本,以便您的应用即使暂时失去网络连接也能正常工作。

在 Firestore 中我们发现相反的情况,要禁用持久性,我们需要将 PersistenceEnabled 选项设置为 false。这意味着您告诉 Firestore 不要在用户设备上创建数据库的本地副本,这意味着除非您连接到 Firebase 服务器,否则您将无法查询您的数据库。因此,如果没有数据库的本地副本,并且如果断开连接,则会引发异常。这就是为什么使用OnFailureListener 是一个好习惯的原因。

更新 (2018-06-13): 正如@TalBarda 在他的回答中提到的,现在可以从 16.0.0 SDK 版本更新开始。所以我们可以借助DocumentReference.get(Source source) 和Query.get(Source source) 方法来实现这一点。

默认情况下,get() 通过等待来自服务器的数据尽可能尝试提供最新数据,但如果您处于离线状态且无法访问服务器,它可能会返回缓存数据或失败。可以通过 Source 参数更改此行为。

所以我们现在可以将作为参数传递给DocumentReferenceQuery 源,以便我们可以强制从server onlychache only 检索数据或尝试服务器并回退到缓存.

所以现在这样的事情是可能的:

FirebaseFirestore db = FirebaseFirestore.getInstance();
DocumentReference docIdRef = db.collection("tests").document("fOpCiqmUjAzjnZimjd5c");
docIdRef.get(Source.SERVER).addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() 
    @Override
    public void onSuccess(DocumentSnapshot documentSnapshot) 
        //Get data from the documentSnapshot object
    
);

在这种情况下,我们强制仅从服务器检索数据。如果您想强制仅从缓存中检索数据,您应该将作为参数传递给get() 方法Source.CACHE。更多信息here.

【讨论】:

如果 Firestore 设计为无论如何都从缓存中检索数据(断开连接后),那么“setPersistenceEnabled(false)”功能有什么用处? 我在更新的答案中解释了为什么 setPersistenceEnabled(false) 功能适用。请看一看。【参考方案3】:

根据Cloud Firestore16.0.0 SDK更新,现在有解决这个问题的办法:


您现在可以选择是要从服务器还是仅缓存中获取数据,例如this(仅服务器示例):

DocumentReference documentReference= FirebaseFirestore.getInstance().document("example");
documentReference.get(Source.SERVER).addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() 
    @Override
    public void onSuccess(DocumentSnapshot documentSnapshot) 
            //...
    
);

仅用于缓存,只需将上面的代码更改为Source.CACHE


默认情况下,这两种方法仍然尝试服务器并回退到缓存。

【讨论】:

如何为StreamBuilders 执行此操作? 一开始它会从缓存中提供数据,即使在将 Source 设置为 SERVER 之后也是如此。【参考方案4】:

FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder() .setPersistenceEnabled(false) .build(); dbEventHome.setFirestoreSettings(settings);

通过设置它总是从服务器获取。

【讨论】:

以上是关于无法在 Firestore 中禁用离线数据的主要内容,如果未能解决你的问题,请参考以下文章

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

在 Firestore REST API 中查询嵌套对象

Cloud Storage 是不是与 Firestore 同步离线工作

Firestore使用Rest API更新文档字段

离线缓存数据的 Firestore 定价说明

在线/离线用户功能 Firestore 或实时的更好解决方案是啥?