Java Firebase onChildRemoved()和removeValue()处理时间敏感操作时出现问题
我有一个应用程序,它提供了一些东西的报价。我的想法是,我在自己创建的另一个应用程序上添加了该服务,然后同时在用户设备上显示 我只需要一个用户就可以接受报价,因此当第一个用户单击报价参考上的I do call removeValue()时,报价将从数据库和其他用户的recyclerview中正确删除 问题是,当两次单击同时发生时,提供被删除,但onChildRemoved()没有时间被调用,因此两个用户现在拥有相同的提供 有没有其他办法让这个操作更精确、更省时 根据svi.data的建议更新我在用户单击时尝试了这段代码,但仍然出现了相同的问题Java Firebase onChildRemoved()和removeValue()处理时间敏感操作时出现问题,java,android,firebase,firebase-realtime-database,Java,Android,Firebase,Firebase Realtime Database,我有一个应用程序,它提供了一些东西的报价。我的想法是,我在自己创建的另一个应用程序上添加了该服务,然后同时在用户设备上显示 我只需要一个用户就可以接受报价,因此当第一个用户单击报价参考上的I do call removeValue()时,报价将从数据库和其他用户的recyclerview中正确删除 问题是,当两次单击同时发生时,提供被删除,但onChildRemoved()没有时间被调用,因此两个用户现在拥有相同的提供 有没有其他办法让这个操作更精确、更省时 根据svi.data的建议更新我在用
offerUnAnsweredRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
boolean stillThere = false;
for (DataSnapshot offerSnap : dataSnapshot.getChildren()) {
if (offerSnap.getKey().equals(requestedOffer.getCurrentNodeKey())) {
stillThere = true;
}
}
if (stillThere) {
Timber.d("We have it " + requestedOffer.getEmployeeKey());
Toast.makeText(getContext(), "Welcome Dear ", Toast.LENGTH_SHORT).show();
offerUnAnsweredRef.child(requestedOffer.getCurrentNodeKey()).removeValue();
} else {
Toast.makeText(getContext(), "Go Away Bear", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
更新2
事实上,这个解决方案是建立在svi.data的基础上的,并进行了一些修改,所以我想分享工作代码,以便在任何人遇到类似情况时提供帮助
offerUnAnsweredRef.child(requestedOffer.getCurrentNodeKey()).runTransaction(new Transaction.Handler() {
@NonNull
@Override
public Transaction.Result doTransaction(@NonNull MutableData mutableData) {
RequestedOffer o = mutableData.getValue(RequestedOffer.class);
if (o == null) {
return Transaction.abort();
}
if (o.getEmployeeKey() == null) {
o.setEmployeeKey(employee.getUid());
mutableData.setValue(o);
return Transaction.success(mutableData);
} else {
return Transaction.success(mutableData);
}
}
@Override
public void onComplete(DatabaseError databaseError, boolean b,
DataSnapshot dataSnapshot) {
// check if the transaction completed successfully
// or if it failed
RequestedOffer o = dataSnapshot.getValue(RequestedOffer.class);
if (o.getEmployeeKey() == employee.getUid()) {
getActivity().runOnUiThread(() -> Toast.makeText(getActivity(), "Hello", Toast.LENGTH_SHORT).show());
DatabaseReference databaseReference = FirebaseFactory.getDatabase()
} else {
getActivity().runOnUiThread(() -> Toast.makeText(getActivity(), "NO", Toast.LENGTH_SHORT).show());
}
}
因为正如文件所说
公共抽象事务。结果doTransaction(可变数据currentData)
将使用此位置的当前数据调用此方法(可能多次)。它负责检查该数据并返回事务。结果指定该位置所需的新数据或该事务应中止
因此,我添加了代码来签入onComplete,以确保它只调用一次。据我所知: 1) 您有一个用于添加优惠的特定应用程序(由您提供) 2) 您有另一个应用程序(由用户)阅读优惠 3) 如果是这种情况,那么两个应用程序使用相同的项目 4) 当用户单击某个报价时,他/她将获得该报价,然后您将从数据库中删除该报价 5) 现在,当两个用户单击同一个报价时,没有时间从另一个用户的列表中删除该报价,因此他们最终会得到相同的报价 现在看来,你不想让用户得到同样的优惠,问题其实是时间问题 可能的解决方案: 1) 当用户单击某个报价时,可以运行ValueEventListener()到数据库中的
报价
节点,并检查该报价是否存在
2) 如果报价存在,则向他/她提供报价并将其删除
3) 现在,当两个用户单击同一个报价时,我提到的ValueEventListener将在您做出反应之前为您提供一段时间
4) 因此,用户不应该以同样的优惠结束
希望它能解决你的问题
更新:
由于这是用户之间的竞争条件,现在是讨论事务的时候了。Firebase提供了一种很好的方法,可以直接读取和写入同一节点的并发更新(这就是您的情况)
我希望您的数据库如下所示:
Offers
|
|------offer_id_1
|
|-----taken:false
|-----......
|-----......
|
|-------offer_id_2
|
|------taken:false
|------......
|------......
让我解释一下上面的结构,您从另一个应用程序发布的每个报价在默认情况下都会有一个名为take
的标志,并且默认值应该是false
现在,正如您在上面所看到的offer\u id\u 1
和offer\u id\u 2
是为offer提供的推送id或随机id(当用户单击offer时,您必须获得此键的引用……我想您知道如何操作)
当然,在我们开始之前,你们应该为你们的帖子建立一个模型类,我们称之为Offer
它只是一个类:
public class Offer{
public boolean taken;
......
......
}
以下函数是有人单击报价后您将调用的函数(我们将使用事务):
现在,当用户在列表中单击一个offer时,存储offer的id并将其传递给上面的函数,如下所示
//after user clicks
String offer_id = .......
//run transaction
RunTransactionFor(offer_id);
注意:交易只能在线进行,不能离线进行。哇,你比我解释得更清楚。但没有:(这种方法不太管用,我曾尝试使用addListenerForSingleValueEvent,每次单击只听一次引用,但当同时从两个设备尝试并单击时,两者都受到欢迎。)dear@covans检查更新,希望有帮助。干杯,伙计,你帮我解决了一周的事务,我以前对这些事务一无所知。谢谢你
//after user clicks
String offer_id = .......
//run transaction
RunTransactionFor(offer_id);