Firebase Runtransaction Not Working - Mutabledata Is Null

Firebase runTransaction not working - MutableData is null

You'll want to follow the pattern used in the Firebase documentation for handling transactions and handle the case where there's no current value your transaction callback:

public Transaction.Result doTransaction(MutableData currentData) {
long value = 0;
if(currentData.getValue() != null) {
String numQuestions = (String) currentData.getValue();
value = Long.parseLong(numQuestions, 16);
}
value++;
String incHex = Long.toHexString(value);
currentData.setValue(incHex);
return Transaction.success(currentData);
}

The reason you need to do this is that Firebase may (and often will) execute your transaction callback multiple times and you need to cater for that.

  1. When you first call runTransaction() the Firebase client will immediately invoke your doTransaction() callback with its current guess for the current data. Quite often this will be null.
  2. Your code returns the next value based on the current value. In the case above, if the current value was null the new value will be 1.
  3. The Firebase client then sends both the assumed current value and the new value to the server.
  4. If the actual stored value is the same as the assumed current value, the Firebase server writes the new value you specified.
  5. If the actual stored values is different from the assumed current value, the Firebase server rejects the new value and sends the actual current value to the client.
  6. At this stage the client goes back to step 1, with the now updated assumed current value.

If this does not explain the behavior you're seeing, you might want to check what values are passed into onComplete().

Firebase Transaction MutableData showing Nil

This is the expect behavior. When you start a transaction the SDK immediately calls your transaction handler with its best guess of the current value of the node. Most often that guess will be nil, as the client has no better knowledge yet.

So you will have to not abort the transaction, but instead set another value on the mutable data, for example 0. It doesn't really matter much what that value is, as the transaction will be retried anyway.

For more background on this, see:

  • Firebase realtime database transaction handler gets called twice most of the time, with an ASCII chart of the flow
  • Firebase runTransaction not working - MutableData is null
  • how to handle null values on firebase transaction api

Avoid obtaining null currentData at first reading in a Firebase transaction

On the first invocation of doTransaction the currentData will likely be empty. This is not related to the existence of data in the database, but on knowledge of that data in the client. It being empty is fully expected, and your code should handle it.

So if the existing data would not exist, what should the transaction do? Even just leaving it empty is fine, as long as you do something valid it will auto-correct on the next try (or one of the ones after that).

Also see:

  • Firebase runTransaction not working - MutableData is null
  • how to handle null values on firebase transaction api

ValueEventListener returning a snapshot with null value for a brief second after .runTransaction()

firebaser here

Getting null as the current value in your transaction handler initially is the expected behavior. The transaction handler is called with the current guess of the client for the value, which often will be null. If the initial guess is incorrect, your transaction handler will be called again with an updated guess for the current value. See a.o. https://stackoverflow.com/a/57134276/209103

The solution is to return a value if you get null, even if you know that value will never actually be written to the database:

if (anObject != null) {
...

}
else {
mutableData.setValue("This is needed to get the correct flow"); // br>}

If you don't want Firebase to fire local events for the transaction values right away, but only once the transaction is confirmed, you can pass a boolean second argument to runTransaction to indicate this:

https://firebase.google.com/docs/reference/android/com/google/firebase/database/DatabaseReference#runTransaction(com.google.firebase.database.Transaction.Handler,%20boolean)

Firebase Transaction: When data is downloaded and why every ValueEventListener get called with null when a transation is running

When you execute this code:

FirebaseDatabase.getInstance().getReference()
.child("...")
.child("building")
.runTransaction

Firebase will read all data under the .../building path. For this reason it is recommended to run transactions as low in the JSON tree as possible. If this is not an option for you, consider running the transaction in something like Cloud Functions (maybe even with maxInstances set to 1) to reduce the contention on the transaction.


To you second question: this is the expected behavior. Your transaction handler is immediately called with the client's best guess to the current value of the node, which in most cases will be null. While this may never be possible in your use-case, you will still have to handle the null by returning a value.

For a longer explanation of this, see:

  • Firebase realtime database transaction handler gets called twice most of the time
  • Firebase runTransaction not working - MutableData is null
  • Strange behaviour of firebase transaction

Android Java Firebase runTransaction deletes values when classes are not exactly the same

A transaction must provide the complete new value for the location that you run it on. You can't run a transaction on API.ref.databaseSpecificUser(id) and then only provide a value for a single property under it.

You have a few options in your scenario:

  1. Don't use the (incomplete) User class for calling setValue(), but instead only update the specific property directly on the mutableData. So that'd be something like mutableData.child("count").setValue(42). This way the mutableData will still contain all properties, even when the User class doesn't.

  2. Run the transaction directly on the property that you want to modify, so: API.ref.databaseSpecificUser(id).child("count").runTransaction(.... That way the mutableData will only be for the property that you're modifying, so nothing else will be deleted. Here too, you won't be using your User class, as you're reading/writing a single property.

  3. Use the newer ServerValue.increment(1) operation to increment the count. This operation is much more efficient, and typically leads to simpler code. Something like: ServerValue.increment(1).child("count").setValue(ServerValue.increment(1));



Related Topics



Leave a reply



Submit