5

Take a look at this GIF I recorded:

(GIF

This is the database of a counter app I'm making. When a user increments, count gets added along with the count under

users:{
   UID:{
     count: x
   }
}

However, if you can notice in the GIF, sometimes, the upper count gets incremented but the one under users doesn't. Here's the code I'm saving it with:

database = database.child("users").child(auth.getCurrentUser().getUid()).child("count");
    final DatabaseReference finalDatabase = database;
database.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            //Get the latest int
            final int[] i = {Integer.parseInt(button.getText().toString())};
            //add to the user's count with an onFailureListener
            finalDatabase.setValue(i[0]++).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    Log.e(TAG,"Adding user's count failed: " + e.getMessage());
                }
            }).addOnSuccessListener(new OnSuccessListener<Void>() {
                @Override
                public void onSuccess(Void aVoid) {
                    //Now add to the original
                    DatabaseReference database = FirebaseDatabase.getInstance().getReference();
                    database.child("Campaigns").child(key).child("count").setValue(i[0]++).addOnFailureListener(new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            Log.e(TAG, "Error: " + e.getMessage());
                        }
                    });
                }
            });

None of the onFailure methods get called. So why is this happening?

Ali Bdeir
  • 4,151
  • 10
  • 57
  • 117
  • can you please show where the references are being made – Veeresh Charantimath Aug 12 '16 at 06:14
  • Are you trying to listen to an update and update another field? – Joshua Aug 12 '16 at 06:19
  • @Joshua yes, should I include that too? – Ali Bdeir Aug 12 '16 at 06:21
  • 1
    Ok, I may know what the problem is. The `OnFailureListener` you added is called only when it fails to update but not fail to listen. My guess is you app didn't receive the update event, so it does not perform the task. The may caused by not stable internet connection or some other reasons. – Joshua Aug 12 '16 at 06:29
  • But I would say this is not a good practice, especially this is an mobile application. Usually, this kind of update should be do the server, not the client. Also, why would you keep same value at two different location? – Joshua Aug 12 '16 at 06:29
  • Can you show me how I can use Server for this? – Ali Bdeir Aug 12 '16 at 06:33
  • @Joshua one `count` is the TOTAL count, and the other count is each user separately. If you give me an example on how to do this via Server, then you're answer will be accepted. – Ali Bdeir Aug 12 '16 at 07:38
  • @AbAppletic You cannot do that with Firebase only. Also, you will face race condition on the total count. – Joshua Aug 12 '16 at 07:45
  • just an idea, why not count the total count by just listening to the `users` node? if you want it to be real-time, use a `ChildEventListener` to that reference so you can get `childAdded` and `childChanged` callback if the value is added or changed – Wilik Aug 12 '16 at 08:19
  • @Wilik can you post this as an answer with an example? I didn't really understand – Ali Bdeir Aug 12 '16 at 08:43
  • @AbAppletic ok sure – Wilik Aug 12 '16 at 09:17

1 Answers1

1

You can instead listen to the users node to count the total count. Here's an example

private Map<String, Long> userCount = new HashMap<>();
private Long totalCount = 0L;

private void addTotalCountListener() {
    FirebaseDatabase.getInstance().getReference().child("users").addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            User user = dataSnapshot.getValue(User.class);
            userCount.put(dataSnapshot.getKey(), user.getCount);
            totalCount += user.getCount();
        }

        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) {
            // subtract the total count with the previous count
            totalCount -= userCount.get(dataSnapshot.getKey());
            // then add the new count
            User user = dataSnapshot.getValue(User.class);
            userCount.put(dataSnapshot.getKey(), user.getCount);
            totalCount += user.getCount();
        }
    });
}
Wilik
  • 7,630
  • 3
  • 29
  • 35
  • But I'm not sure if this is what I want. What I'm trying to achieve is that when the user clicks on a button, his count along with the other count gets added. The only time I'm listening for an event is when I ADD to count, then my text gets updated – Ali Bdeir Aug 12 '16 at 09:27
  • the problem is, a race condition may occur if multiple users click on the button at the same time. you might want to use transaction operation to avoid this but it's quite complicated in my opinion, look at this guide [save data as transactions](https://firebase.google.com/docs/database/android/save-data#save_data_as_transactions). if you don't want to listen to all of the users' child, you can run my solution as the server to update the root's `count`, each user then can listen to that root `count` to get the latest total count. – Wilik Aug 12 '16 at 09:45
  • Thanks, I'm gonna remove Satan off your rep – Ali Bdeir Aug 12 '16 at 09:59