【问题标题】:Android Firebase how to handle real time server to local database connectionAndroid Firebase如何处理实时服务器到本地数据库的连接
【发布时间】:2019-06-07 17:02:05
【问题描述】:

关于这个话题和ChildEventListener的类似问题,没有相关的答案,所以这是我的。

我有一个本地 SQLite 数据库,其中包含所有数据,我也有 Firebase 实时数据库,我正在更新所有用户的新条目或实时更改。我目前正在使用ChildEventListener 进行如下操作:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getDatabase().getReference();
    DatabaseReference childRef = rootRef.child("my_root");

    ChildEventListener eventListener = new ChildEventListener()
    {
        ....
    };
    childRef.addChildEventListener(eventListener);

至于功能,使用此代码,我可以实时更改子项、获取新条目、删除子项以及我需要的一切,但有一个问题。当监听器的这个特定活动加载时,onChildAdded 监听器会被这个根上的每个孩子调用大量的时间,如文档中所述:

child_added 为每个现有的孩子触发一次,然后在每次将新的孩子添加到指定路径时再次触发

所以我想把注意力集中在我真正需要的东西上,我已经做到了:

rootRef.orderByKey().startAt("-WhatTF123456789")...

但后来我失去了我的 CRUD 功能,因为它正在侦听新条目而不是所有条目。

所以我想出了一个解决方案。保留对 FireBase 数据库所做的所有更改的节点,以及所有已读取并对本地数据库进行更改的用户的节点,以了解谁需要更新,然后使用 addChildEventListener 到此特定节点。但这似乎是多余的。

我有什么办法来处理这种情况?

【问题讨论】:

  • 您的选择是 1) 忽略冗余子节点,2) 查询从第一个新子节点开始。第二种选择当然是首选,因为第一种下载的数据太多。你的一天“但后来我失去了我的 CRUD 能力”。你能详细说明你的意思吗?或者更好的是,在代码中显示它?
  • @FrankvanPuffelen 我的代码基本上是上面显示的ChildEventListener 裸露,其中包含它的实现方法。当我说我正在失去我的 CRUD 功能时,这是因为当我正在收听最后一个孩子时,例如:childRef.orderByKey().limitToLast(1),我只在这个特定的最后一个孩子上获得更新和删除回调。我想知道节点上的所有这些,所以我不必使用第一个选项。还是您在谈论其他事情?我在这里错过了什么吗?

标签: java android firebase firebase-realtime-database


【解决方案1】:

onChildAdded 侦听器会为该根上的每个子级调用无数次。

正如您已经提到的以及文档所述,这是预期的行为。通常,不建议在包含大量数据的节点(根节点)上附加ChildEventListener。请注意这种做法,因为在下载大量数据时,您可能会收到如下错误:OutOfMemoryError。发生这种情况是因为您隐式下载了您正在收听的整个节点,以及它下面的所有数据。该数据可能以简单属性或复杂对象的形式出现。所以可以认为是资源和带宽的浪费。在这种情况下,最好的方法是尽可能扁平化数据库。如果您是 NoSQL 数据库的新手,这种做法称为反规范化,是 Firebase 的常见做法。为了更好地理解,我建议您看一下:

还请注意,当您复制数据时,需要牢记一件事。与添加数据的方式相同,您需要对其进行维护。换句话说,如果你想更新/删除一个项目,你需要在它存在的每个地方都这样做。

我还建议您从以下帖子中查看我的答案的最后一部分:

它适用于 Cloud Firestore,但同样的规则适用于 Firebase 实时数据库。

但后来我失去了我的 CRUD 功能,因为它正在侦听新条目而不是所有条目。

Firebase 中的一切都与听众有关。您无法获得节点内对象的实时更新,除非您正在监听它们。因此,您不能限制结果并期望从您未收听的对象中获取更新。如果您需要获取节点内所有对象的更新,则需要监听所有对象。因为这种方法根本不实用,您可以使用上述非规范化,也可以通过使用有助于限制从数据库获取的数据量的查询来限制结果。关于您的解决方案,第二种方法更受欢迎,但您也可以考虑另一种方法,即根据timestamp 属性或根据您需要的任何其他属性以较小的块加载数据.

编辑:根据您的评论:

能否请您为每种解决方案(1.denormalization,2.my 解决方案)提供测试,检查带宽和资源的使用情况以及真正首选的解决方案?

所有数据都经过建模以允许应用所需的用例。不幸的是,我无法进行测试,因为它实际上取决于应用程序的用例及其包含的数据量。这意味着适用于一个应用程序的内容可能不足以用于另一个应用程序。所以测试可能对每个人都是正确的。非规范化过程或您的解决方案完全取决于您打算如何查询数据库。在上面的列表中,我添加了一个新资源,这是我对denormalization tehnique in NoSQL databases 的回答。希望它也能帮助推荐访问者。

【讨论】:

  • 嘿,抱歉耽搁了我目前正在休假,只是让你知道我已经实现了使用节点的解决方案,其中包含所有更改、添加、删除firebase 数据库。唯一的监听器是这个节点,用户获得实时更新,带宽的使用非常低。即使我已经在应用程序上实现了我的解决方案,您能否为每个解决方案(1.非规范化,2.我的解决方案)提供测试,检查带宽和资源的使用以及哪个是真正首选的?这当然是为将来遇到此问题的用户准备的。
  • 别担心我的朋友,我知道系统是如何工作的。在这里,带上你的互联网积分;)
【解决方案2】:

我有类似的要求,FirebaseRoom,虽然我已经解决了这个问题:

public class BaseModel extends BaseObservable implements IDataModel {

    /** Sqlite default PK */
    private int itemId = 0;

    /** Firebase uniqueId */
    @ColumnInfo(name = SqliteBaseHelper.KEY_FIREBASE_UNIQUE_ID)
    protected String uniqueId = null;

    /** Firebase lastSync */
    @ColumnInfo(name = SqliteBaseHelper.KEY_FIREBASE_LAST_SYNC)
    protected long lastSync = 0;

    ...
}

这意味着,当本地记录具有KEY_FIREBASE_UNIQUE_IDnull 并且KEY_FIREBASE_LAST_SYNC0 时,必须将其插入Firebase - 否则它会在运行同步时检查@ 987654329@,如果需要更新本地或远程记录。这是因为主要问题是,当远程插入时,ChildEventListener 将尝试将副本同步到同一个客户端 - 除非在本地和远程有同步状态的此类指示器。本地主键可能因客户端而异(取决于它们离线多长时间以及在离线状态期间本地插入的记录数),而合成 KEY_FIREBASE_UNIQUE_ID 用于识别它们;这是“成功的关键”。

【讨论】:

    【解决方案3】:

    我会创建一个名为MaintenanceUpdate 的根节点。 所有客户端都订阅了此处的更改。 只要MaintenanceUpdate 变为 = true,所有客户端都会取消订阅对主“数据库”的更改。然后(当MaintenanceUpdate = false)再次重新订阅。 此时您正在更新数据库。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-16
      • 2014-05-19
      • 2014-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多