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

时间:2014-10-13 22:23:49

标签: android firebase firebase-realtime-database

使用适用于Android的Firebase,我使用以下数据结构来处理插槽数量有限的聊天室:

/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)设置为{{1因为否则您将从事务中接收事件,尽管它可能不会成功。
  2. 即使将false(Android)或fireLocalEvents(JavaScript)设置为applyLocally,该引用上false的事件也会在之前触发 >您的交易在onChildChanged(...)成功返回。这是预期的行为吗?
  3. 对于这个特殊情况,这意味着我会在我知道我自己之前通知聊天室已满(onComplete(...) em>是获得最后一个位置的人(在ChildEventListener.onChildChanged(...)中)。

    我们假设,如果房间已满......

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

    如果我想这样做,我必须将完整的逻辑移到Transaction.Handler.onComplete(...),因为那是我首先收到事件的地方,对吗?否则,在我知道我是最后一个位置的人之前,房间将被隐藏。

    有什么想法吗?

1 个答案:

答案 0 :(得分:1)

这实际上是使Firebase成为一款了不起的应用程序的组件之一,可以为您节省大量代码。要了解为什么这对您有利,我们需要暂时退一步并讨论延迟补偿和离线功能。

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

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

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

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

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