如何启用 Firebase 实时数据库离线持久性?

Posted

技术标签:

【中文标题】如何启用 Firebase 实时数据库离线持久性?【英文标题】:How to enable Firebase Real time database Offline persistence? 【发布时间】:2020-05-31 15:03:39 【问题描述】:

在我的 MainActivity 中,我启用了如下所示的 firebase 持久性,

// Imports ** 

private  lateinit var mDatabase : FirebaseDatabase

val md = FirebaseDatabase.getInstance().setPersistenceEnabled(true)

class MainActivity: AppCompatActivity() 

override fun onCreate(savedInstanceState: Bundle?)  
// bla bla 


在初始化 MainActiviy 之后,我的 Activity2 开始销毁 MainActivity。在我的 Activity2 视图模型中,我正在初始化来自服务器的所有数据,如下所示,

class AppMainActivityViewModel(application: Application) : androidViewModel(application) 

lateinit var user_data_ref : DatabaseReference
lateinit var user_data_ref_lis : ValueEventListener

init 
        user = FirebaseAuth.getInstance().currentUser?.uid!! 

fun updateDashboard()
 user_data_ref = FirebaseDatabase.getInstance().getReference("Users/$user")
user_data_ref_lis = user_data_ref.addValueEventListener(object : ValueEventListener 

            override fun onCancelled(p0: DatabaseError) 
            
            override fun onDataChange(p0: DataSnapshot) 
                userdata.value = p0.getValue(UserModel::class.java)
            
        )


override fun onCleared() 
        super.onCleared()
        user_data_ref.removeEventListener(user_data_ref_lis)
    

    

如果我第一次使用互联网运行我的应用程序,我假设我的听众现在已经离线缓存数据,然后我退出我的应用程序然后在没有互联网的情况下打开,我在这里预计本地缓存的数据会立即触发 onData 更改,但我的惊喜 onData 更改从未被触发。然后我将我的代码更改为对我的 user_data_ref 保持同步,然后它在离线模式下运行良好。

每次用户打开应用程序时,都会下载一堆旧历史(大约 30 个参考,每个参考 100kb,一些旧历史永远不会改变)。这大大增加了我在一段时间内的带宽消耗,因为每次使用当前逻辑下载新文件时。我启用持久性的主要目标是减少带宽消耗。

以下是我现在遇到的一堆问题,

    根据文档,ValueEvent 监听器应该足以缓存数据,为什么它在我的情况下不起作用?

    在持续检查更新时,保持同步是否会增加我的带宽消耗?

    即使我的活动被破坏,这是否会保持同步真实运行?

    1234563下次会下载这 100 kb 还是只下载 1 kb?

【问题讨论】:

【参考方案1】:

我启用持久性的主要目标是减少带宽消耗。

磁盘持久性的目标是让应用即使在用户没有互联网连接的情况下也能启动和运行。虽然磁盘持久性可能还可以减少一些数据下载,但这并不能保证,也不是其主要目的。

为了减少带宽消耗,您应该读取更少的数据。只要应用程序处于活动状态,在节点上调用 keepSynced(true) 将使该节点保持同步。如果节点经常变化,而你只需要零星的数据,这几乎可以保证浪费带宽。在这里,保持节点同步的目标也不是减少带宽使用,而是保持数据“新鲜”,以防在用户未连接时需要它。

对于您的问题:

    根据[文档],ValueEvent 监听器应该足以缓存数据,为什么它在我的情况下不起作用?

无法准确说明为什么没有缓存数据。但是,如果您的onDataChange 没有被调用,则可以安全地假设数据也不会写入磁盘缓存。

问题排查的第一步是实施onCancelled,您切勿将其留空。它的最小实现是:

override fun onCancelled(p0: DatabaseError) 
    throw p0.toException();

    在持续检查更新时,保持同步是否会增加我的带宽消耗? 即使我的活动被破坏,这是否会保持同步真实运行?

当您调用ref.keepSynced(true) 时,它会将一个空侦听器附加到ref。这意味着只要应用程序正在运行,ref 处的数据就会在内存中保持最新(如果您启用了磁盘持久性,则在缓存中)。

如前所述,如果数据更新频繁且不经常使用,则最终可能会使用比仅在需要时附加侦听器更多的带宽。如前所述:当您需要节点的数据是新鲜的时,您应该调用ref.keepSynced(true)

不可能在每种情况下都说明保持节点同步的效果 对带宽使用有影响。您必须根据了解每个 API 的实际作用以及它的用途来衡量和推断。

    如果我将 keepsynced true 设置为大小为 100kb 的数据库引用,如果在我的 ref 中发生子更新,这将是 1kb 的变化。下次会下载这 100 kb 还是只下载 1 kb?

两者都不是。在这种情况下,Firebase 会执行所谓的增量同步。 SDK 计算本地数据的哈希列表,并将其发送到服务器。服务器将这些与自己的哈希值进行比较,然后只发回已更改的数据。结果通常应该比发回整个快照要小,但要小多少取决于该位置有多少数据以及更改了多少。

另见:

Firebase : What is the difference between setPersistenceEnabled and keepSynced? Firebase setPersistenceEnabled(true) what about the downloaded data Does firebase web client download data every time I subscribe for a certain database path?(尤其是我回答的 cmets)

【讨论】:

嗨弗兰克,我是否在我的活动中正确初始化设置持久性启用?我在onCreate 之前打电话。我必须为我的所有活动做些什么吗?有什么方法可以检查是否启用了持久性? 您只需调用一次setPersistenceEnabled(true),然后再调用任何其他使用 Firebase 的代码。它通常在内容提供商中完成,但如果它在你现在拥有的地方工作,那也很好。

以上是关于如何启用 Firebase 实时数据库离线持久性?的主要内容,如果未能解决你的问题,请参考以下文章

如何离线存储 Firebase 分析数据超过 72 小时?

何时在 Firebase 上启用离线功能调用完成块?

Flutter:如何删除等待以利用 Firebase 离线持久性?

Android 中的 Firebase 数据库持久性错误

我们如何将数据写入firebase实时数据库?即使启用了读/写,但似乎不起作用

1 小时后身份验证令牌无效 - Firebase 中的磁盘持久性