【问题标题】:onDataChange stuck in infinite looponDataChange 陷入无限循环
【发布时间】:2018-06-04 09:24:15
【问题描述】:

我正在尝试使用 Firebase 为餐厅和酒吧创建评分系统。到目前为止,我能够阅读和编写个人评级。我遇到的问题是,为了计算特定餐厅的平均评分,我需要获取存储的评分数量和存储的所有评分的总值。目前,我正在努力存储收视率。这是我的代码

Query RetrieveRating =  databaseReference.child("ratings").child("porterhouse");
RetrieveRating.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot postSnapshot) {

   //get data from snapshot
    String  data = postSnapshot.child("numRating").getValue().toString();

    if (!data.equals(null)) {
        String numRating = (String) postSnapshot.child("numRating").getValue();

        count = Integer.valueOf(numRating);
        count++;

        ratingCounter = Integer.toString(count);

        databaseReference.child("ratings").child("porterhouse").child("numRating").setValue(ratingCounter);
     }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {

    }
});

发生的情况是它获取当前存储的值,将其加 1 并将其写回数据库,但是每次存储时都会调用 onDataChange() 方法,一次又一次地加 1无限循环。 我的问题是,我是否可以进行任何更改以防止这种情况发生,甚至可以采用不同的方式进行配置? 谢谢

更新

json代码如下:

    {
      "ratings" : {
        "porterhouse" : {
          "numRating" : "0",
          "totalRating" : "0"
        }
  }

【问题讨论】:

  • 发布你的 json 结构
  • @MartinDeSimone 更新以显示 json 代码的相关部分
  • 这确实会根据您的代码创建一个循环,因为 ChildEventListener 会侦听该特定路径上的所有更改,并且在侦听器内更改该路径会一次又一次地触发它
  • 您能发布您的整个 JSON 数据库架构吗?

标签: android firebase firebase-realtime-database


【解决方案1】:

使用 addListenerForSingleValueEvent

RetrieveRating.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot postSnapshot) {

            //get data from snapshot
            String  data = postSnapshot.child("numRating").getValue().toString();

            if (!data.equals(null)) {
                String numRating = (String) postSnapshot.child("numRating").getValue();

                count = Integer.valueOf(numRating);
                count++;

                ratingCounter = Integer.toString(count);



                databaseReference.child("ratings").child("porterhouse").child("numRating").setValue(ratingCounter);

            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

您还应该使用 firebase 事务来增加计数器

【讨论】:

  • 谢谢马丁,工作完美。非常感谢您的帮助
【解决方案2】:

虽然 Martin 的回答解决了无限循环,但它在您的方法中留下了问题。如果两个用户几乎同时对餐厅进行评分,他们的更改可能会相互干扰。

要解决这个问题,正如马丁所说,你应该use a transaction

DatabaseReference ratingRef =  databaseReference.child("ratings/porterhouse/numRating");
postRef.runTransaction(new Transaction.Handler() {
    @Override
    public Transaction.Result doTransaction(MutableData mutableData) {
        int count;
        try {
            count = Integer.parseInt(mutableData.getValue(String.class));
        } catch (NumberFormatException e) {
            count = 0;
        }
        count++;
        mutableData.setValue(Integer.toString(count));
        return Transaction.success(mutableData);
    }

    @Override
    public void onComplete(DatabaseError databaseError, boolean b,
                           DataSnapshot dataSnapshot) {
        Log.d(TAG, "countTransaction:onComplete:" + databaseError);
    }
});

我不太确定您为什么将计数器存储为字符串。我强烈建议将其存储为数字,在这种情况下,此代码会变得更简单:

DatabaseReference ratingRef =  databaseReference.child("ratings/porterhouse/numRating");
postRef.runTransaction(new Transaction.Handler() {
    @Override
    public Transaction.Result doTransaction(MutableData mutableData) {
        Integer count = Integer.parseInt(mutableData.getValue(Integer.class));
        if (count == null) count = 0;
        count++;
        mutableData.setValue(count);
        return Transaction.success(mutableData);
    }

    @Override
    public void onComplete(DatabaseError databaseError, boolean b,
                           DataSnapshot dataSnapshot) {
        Log.d(TAG, "countTransaction:onComplete:" + databaseError);
    }
});

【讨论】:

    【解决方案3】:

    如果有人在添加 addListenerForSingleValueEvent() 之后仍然在努力解决问题,并且您需要在 dataChange() 中增加值,这是一种不好的做法,如上所述,您只需添加一个最初为 false 的布尔对象并在如果 dataChange() 方法仍然为 false => setvalue 并将布尔值设置为 true ,则将上述情况转换为:

    boolean is_added = false;
    
    onDataChange(){
    //after increment and befor setValue()
    if(!is_added){
    //setValue() set what ever you want on that reference 
    is_added = true ;
    }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-05-13
      • 1970-01-01
      • 2013-03-17
      • 2021-02-15
      • 2022-01-23
      • 2021-01-23
      相关资源
      最近更新 更多