0

I'm creating a method that do a work, it increments a value every time onComplete is finish, but it's causing a infinite loop on that field.

For instance when onComplete finishes, the method executes and must increase 100 points, but it takes the points and keep increasing without ever ending.

This is my method:

@Override
public void afterTextChanged(Editable editable) {
                        refTrans.child(finalCurrentUserKey).child(Constants.FIRE_BASE_USER_DRIVER_PLUS).child("birthday").setValue(
                                etBirthday.getText().toString(), new DatabaseReference.CompletionListener() {
                                    @Override
                                    public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
                                        addPoints(finalCurrentUserKey);
                                    }
                                });
                    }

        private void addPoints(final String finalCurrentUserKey){
        // Create a reference to the DB
        final FirebaseDatabase mDatabase = FirebaseDatabase.getInstance();
        final DatabaseReference refPoints = mDatabase.getReference(Constants.FIRE_BASE_USER_DRIVER);
        final DatabaseReference scoreRef = refPoints.child(finalCurrentUserKey).child("score/increaseScore");

        //final Double[] count = new Double[1];
        final String operation = "increaseScore";

        scoreRef.runTransaction(new Transaction.Handler() {
            @Override
            public Transaction.Result doTransaction(MutableData mutableData) {
                Integer score = mutableData.getValue(Integer.class);
                if (score == null) {
                    return Transaction.success(mutableData);
                }

                if (operation.equals("increaseScore")) {
                    mutableData.setValue(score + 1);
                } /*else if (operation.equals("decreaseScore")){
                    mutableData.setValue(score - 1);
                }*/
                //mutableData.setValue(1);
                return Transaction.success(mutableData);
            }

            @Override
            public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {

            }
        });

infinite loop

Marco
  • 2,007
  • 17
  • 28
  • You should look into performing a transaction if you want to increment a value in the database. The way you have it right now can cause incorrect values to appear in the database if there are multiple users all trying to write to the same location at the same time. https://firebase.google.com/docs/database/android/read-and-write#save_data_as_transactions – Doug Stevenson Feb 19 '18 at 22:31
  • @DougStevenson I did already with a transaction same result! – Jhon Jarol Tabares Orozco Feb 20 '18 at 13:26

3 Answers3

0

As Doug mentioned in his comment, for this use case you should use transactions. For this, I recommend you definitely use transactions. You will avoid wrong results if users are trying to increase/decrease the counter in the same time. I have explained here how you can use transactions to increase a score without worrying that in your database can appear incorrect values.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Ok, I´m executing that method inside .setValue( value, new DatabaseReference.CompletionListener() { public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) { addPoints(finalCurrentUserKey);}}); Even with a transaction it creates the infiniti loop – Jhon Jarol Tabares Orozco Feb 20 '18 at 13:48
  • Have you tried to use the exact code as in this **[post](https://stackoverflow.com/questions/48307610/how-to-save-users-score-in-firebase-and-retrieve-it-in-real-time-in-android-stud)**? It will work 100%. – Alex Mamo Feb 20 '18 at 17:35
  • tried same problem, please check picture on initial post, child is on yellow and keep increasing not stop – Jhon Jarol Tabares Orozco Feb 20 '18 at 20:40
  • That infinite loop is most likely happening if are using a loop or you are calling a method too many times. In order to solve this, use only that simple code I provided you and try to see if it works. Is it? – Alex Mamo Feb 21 '18 at 08:54
0
    refPoints.child(finalCurrentUserKey).child("plusPoints").setValue(count[0]); 
// when this statement execute onDataChange method will be called every time

you should use 

    refPoints.child(finalCurrentUserKey).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {

                  // do something

        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {

    }
}); 
    // this is going to call onDataChange method once if the value is changed or not

you should check this post

Salman500
  • 1,213
  • 1
  • 17
  • 35
0

@Alex Mamo thanks for your help, I solved my problem on your way and some validations, here is the way I did, so it can help anyone one day

                if (TextUtils.isEmpty(etBirthday.getText().toString())) {
                obtenerFechaApartir(actvty, etBirthday);
                addPoints(finalCurrentUserKey);
                etBirthday.addTextChangedListener(new TextWatcher() {
                    @Override
                    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

                    }

                    @Override
                    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

                    }

                    @Override
                    public void afterTextChanged(Editable editable) {
                        refTrans.child(finalCurrentUserKey).child(Constants.FIRE_BASE_USER_DRIVER_PLUS).child("birthday").setValue(
                                etBirthday.getText().toString(), new DatabaseReference.CompletionListener() {
                                    @Override
                                    public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {

                                    }
                                });
                    }
                });
            } else {
                obtenerFechaApartir(actvty, etBirthday);
                etBirthday.addTextChangedListener(new TextWatcher() {
                    @Override
                    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

                    }

                    @Override
                    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

                    }

                    @Override
                    public void afterTextChanged(Editable editable) {
                        refTrans.child(finalCurrentUserKey).child(Constants.FIRE_BASE_USER_DRIVER_PLUS).child("birthday").setValue(
                                etBirthday.getText().toString(), new DatabaseReference.CompletionListener() {
                                    @Override
                                    public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {

                                    }
                                });
                    }
                });
            }

It looks like aftertextchanged create a bucle, so be carefull with that guys, greetings!