android - 为什么在 Firebase 中使用事务时 onChildChanged() 在 onComplete() 之前触发?

标签 android firebase firebase-realtime-database

借助 Firebase for Android,我将以下数据结构用于槽数有限的聊天室:

/rooms
  /<roomid, generated by push()>
    /users
      one: null
      two: null
      three: null

为了让我的客户使用其中一个插槽(onethree),我使用以下代码 as provided here (JavaScript version) :

var userid = "myuserid";
var ref = new Firebase("<my-firebase>.firebaseio.com/rooms/<roomid>/users");
ref.transaction(function(users) {
  if (!users.one) {
    // Claim slot 1
    users.one = userid;
    return users;
  } else if (!users.two) {
    // Claim slot 2
    users.two = userid;
    return users;
  } else if (!users.three) {
    // Claim slot 3
    users.three = userid;
    return users;
  }
  // Room is full, abort the transaction.
  return;
}, function(err, committed, snapshot) {
  if (committed && !err) {
    // Joined room successfully.
  } else {
    // Could not join room because it was full.
  }
});

经过一些测试,我发现这是行不通的。以下两个解释为什么它不起作用的假设是否正确?

  1. runTransaction(...) (Android) 或 transaction(...) (JavaScript) 中,您必须设置可选参数 fireLocalEvents (Android) 或 applyLocally (JavaScript) 为 false,否则您将收到来自交易的事件,尽管它可能不会成功。
  2. 即使 fireLocalEvents (Android) 或 applyLocally (JavaScript) 设置为 falseonChildChanged(... ) 该引用将触发 before 您的交易在 onComplete(...) 中成功返回。这是有意为之的行为吗?

对于这种特殊情况,这意味着我将收到聊天室已满的通知(在 ChildEventListener.onChildChanged(...) 中)之前我得到知道 我自己 是获得最后一个位置的人(在 Transaction.Handler.onComplete(...) 中)。

让我们假设,如果房间满了......

  • 我在那里有一个位置,执行了一些代码并启动了一些新的东西。
  • 我没有得到任何位置,我只想从列表中隐藏房间(因为它不再可用)。

如果我想这样做,我必须将完整的逻辑移至 ChildEventListener.onChildChanged(...),因为这是我首先接收事件的地方,对吧?否则,在我知道我是那里最后一个位置的人之前,房间就会被隐藏起来。

有什么想法吗?

最佳答案

这实际上是使 Firebase 成为出色应用并为您节省大量编码的组件之一。为了解为什么这对您有利,我们需要稍等片刻,谈谈延迟补偿和离线功能。

如果您曾经编写过提供实时功能的应用程序,那么您一定会遇到连接错误和临时中断的困惑局面。一旦连接恢复,它会导致大量的 if/else/then 逻辑重试。

Firebase 抽象化了所有这些复杂性,因此您的应用在离线时的工作方式与在线时一样。您仍然可以监听事件、设置/保存/更新数据,并像在线一样继续操作。连接恢复后,将应用事件。

同样,当您在本地执行 set() 操作时,在本地应用更改之前等待服务器回复会非常慢。同样,这会导致大量用于延迟补偿的 if/else 逻辑——当您在本地进行更改时进行跟踪并立即显示它们,这样用户就不会觉得应用没有响应。

Firebase 再次在内部处理这些复杂性。由于生产中 99.9% 的写入操作都会成功,因为错误通常是发送无效内容的原因,我们只是通过触发正确的事件在本地应用更改。然后,如果服务器以这种极端情况回复,我们会通过应用另一个更正状态的事件来编辑更改。

总而言之,当您进行更改时,Firebase 数据最终是一致的。因此,您将立即看到本地事件,这是一件好事。如果在此过程中出现问题,您将看到第二个事件来更正数据,可能会在几百毫秒后发生。

关于android - 为什么在 Firebase 中使用事务时 onChildChanged() 在 onComplete() 之前触发?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26349839/

相关文章:

android - 由于 pcm_read() 在 Galaxy S4 上返回错误 n -5,obtainBuffer 超时

Android - 如何从文档中获取选定的文件名

javascript - Firebase 未定义索引

javascript - Firebase:查询返回 null

java - 在聊天应用程序中获取上次查看时间

android - setVisibility(View.GONE) 不适用于 textview

android - 在操作栏的右上角添加一个按钮

android - Ionic firebase token 始终为空且无 token 刷新

java - 将 DataSnapshot 转换为类对象

ios - 过滤 searchText 到 tableView