使用适用于Android的Firebase,我使用以下数据结构来处理插槽数量有限的聊天室:
/rooms
/<roomid, generated by push()>
/users
one: null
two: null
three: null
我的客户可以使用其中一个广告位(one
到three
),我使用以下代码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.
}
});
经过一些测试,我发现这不起作用。我是否正确,以下两个假设解释了为什么它不起作用?
runTransaction(...)
(Android)或transaction(...)
(JavaScript)中,您必须将可选参数fireLocalEvents
(Android)或applyLocally
(JavaScript)设置为{{1因为否则您将从事务中接收事件,尽管它可能不会成功。false
(Android)或fireLocalEvents
(JavaScript)设置为applyLocally
,该引用上false
的事件也会在之前触发 >您的交易在onChildChanged(...)
成功返回。这是预期的行为吗?对于这个特殊情况,这意味着我会在我知道我自己之前通知聊天室已满(onComplete(...)
) em>是获得最后一个位置的人(在ChildEventListener.onChildChanged(...)
中)。
我们假设,如果房间已满......
如果我想这样做,我必须将完整的逻辑移到Transaction.Handler.onComplete(...)
,因为那是我首先收到事件的地方,对吗?否则,在我知道我是最后一个位置的人之前,房间将被隐藏。
有什么想法吗?
答案 0 :(得分:1)
这实际上是使Firebase成为一款了不起的应用程序的组件之一,可以为您节省大量代码。要了解为什么这对您有利,我们需要暂时退一步并讨论延迟补偿和离线功能。
如果你曾经编写过提供实时功能的应用程序,那么你就会遇到连接错误和临时中断的意外问题。一旦连接恢复,它会导致大量的if / else / then逻辑重试。
Firebase会将所有这些复杂性抽象化,以便您的应用在离线状态下与在线时的工作方式相同。您仍然可以监听事件,设置/保存/更新数据,并继续,就像在线一样。恢复连接后,将应用事件。
同样,当您在本地执行set()操作时,在本地应用更改之前等待服务器回复的速度非常慢。同样,这导致许多if / else逻辑用于延迟补偿 - 当您在本地进行更改并立即显示它们时进行跟踪,以便用户不会感觉应用程序没有响应。
Firebase再次在内部处理这些复杂问题。由于99.9%的生产中的写操作会成功,因为错误通常负责发送无效内容,我们只需通过触发正确的事件在本地应用更改。然后,如果服务器回复该极端边缘情况,我们通过应用另一个纠正状态的事件来编辑更改。
总而言之,当您进行更改时,Firebase数据最终会保持一致。因此,您将立即看到本地事件,这是一件好事。如果在此过程中出现问题,您将看到第二个事件来纠正数据,可能是几百毫秒之后。