3
  ATNRef= FirebaseDatabase.getInstance().getReference("AvailableTokenNumber");
                ATNRef.runTransaction(new Transaction.Handler() {
                    @Override
                    public Transaction.Result doTransaction(MutableData mutableData) {

                        if (mutableData.getValue(int.class ) == 0){
                            mutableData.setValue(2);
                            data.tokenNo = 1;
                            return Transaction.success(mutableData);

                        }else {
                            data.tokenNo=mutableData.getValue(int.class);
                            mutableData.setValue(data.tokenNo + 1);
                            return Transaction.success(mutableData);
                        }
                    }

Whenever the code is run for first time, value of data.tokenNo is 0. After that it is updating correctly as per the database value.

I am not able to figure it out what makes the value of data.token = 0 on every first run of the app/code.

Amir_P
  • 8,322
  • 5
  • 43
  • 92
Gaurav Singh
  • 125
  • 3
  • 12

2 Answers2

5

You should be expecting that the initial snapshot of data available in your transaction could be null during its first execution. Note this from the documentation:

Note: Because doTransaction() is called multiple times, it must be able to handle null data. Even if there is existing data in your remote database, it may not be locally cached when the transaction function is run, resulting in null for the initial value.

Also in the javadoc it says:

This method will be called, possibly multiple times, with the current data at this location.

Expect that the first time your handler is run, it will be dealing with an empty database. Then, when the data there is known (if any), you should be prepared to handle that case also. If you don't want to do anything where there is no data (or unknown data) at the location, simply return a successful Transaction with no changes to mutableData.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • This worked. But the data doesn't get reflected in real time. When the data is retrieved from the database, initially it shows as 0. After certain interaction with UI elements(like pressing button or resuming) that '0' changes to the actual value as in the database. And this doesn't just happen when accessing database for the first time but every time when data is to be retrieved.How can this be avoided? How actual data can be shown in first time itself? – Gaurav Singh Jun 02 '17 at 16:06
  • I'm not sure what you mean. When a transaction completes, the data will be written, and all clients should be able to see it. – Doug Stevenson Jun 02 '17 at 16:35
  • Hope this helps you understand the problem. Consider this scenario: (A) value in database: 3 (B) transaction operation (C) value in app shows as : 0(wrong data) (D) I pressed certain button or kinda refreshed a page (F) value in app now changes to: 3(correct data) – Gaurav Singh Jun 02 '17 at 16:52
  • If you want to see updates to some data in real time, you need an active listener on that data, and react to those changes accordingly. Transactions do not change the way that listeners work. – Doug Stevenson Jun 02 '17 at 20:16
1

Thank you for explaining, @Doug Stevenson. I understand this situation from your answer.

Then I solved this problem with this. This works for me at least.

FirebaseDatabase database = FirebaseDatabase.getInstance();
try {
    database.setPersistenceEnabled(true);
} catch (Exception e) {
    // ignore
}

...

DatabaseReference ref = database.getReference("somewhere");

// Read value from database to synchronize localDB with remoteDB
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

    // Then execute transaction.
    ref.runTransaction(new Transaction.Handler() {
      @NonNull
      @Override
      public Transaction.Result doTransaction(@NonNull MutableData mutableData) {
        ...
        return Transaction.success(mutableData);
      }


      @Override
      public void onComplete(@Nullable DatabaseError databaseError, boolean committed, @Nullable DataSnapshot dataSnapshot) {
        ...
      }

    });
  }
});
wf9a5m75
  • 6,100
  • 3
  • 25
  • 59