Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/178.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Firebase onChildRemoved()和removeValue()处理时间敏感操作时出现问题_Java_Android_Firebase_Firebase Realtime Database - Fatal编程技术网

Java Firebase onChildRemoved()和removeValue()处理时间敏感操作时出现问题

Java Firebase onChildRemoved()和removeValue()处理时间敏感操作时出现问题,java,android,firebase,firebase-realtime-database,Java,Android,Firebase,Firebase Realtime Database,我有一个应用程序,它提供了一些东西的报价。我的想法是,我在自己创建的另一个应用程序上添加了该服务,然后同时在用户设备上显示 我只需要一个用户就可以接受报价,因此当第一个用户单击报价参考上的I do call removeValue()时,报价将从数据库和其他用户的recyclerview中正确删除 问题是,当两次单击同时发生时,提供被删除,但onChildRemoved()没有时间被调用,因此两个用户现在拥有相同的提供 有没有其他办法让这个操作更精确、更省时 根据svi.data的建议更新我在用

我有一个应用程序,它提供了一些东西的报价。我的想法是,我在自己创建的另一个应用程序上添加了该服务,然后同时在用户设备上显示

我只需要一个用户就可以接受报价,因此当第一个用户单击报价参考上的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);