This question already has answers here:
How to return DataSnapshot value as a result of a method?
(6 answers)
getContactsFromFirebase() method return an empty list
(1 answer)
Setting Singleton property value in Firebase Listener
(3 answers)
Closed 1 year ago.
I need to return a read data from Firebase. Here is the code:
private String getInfo(DatabaseReference reference) {
String string = "";
reference.child("xxx").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull #NotNull DataSnapshot snapshot) {
string = snapshot.getValue().toString();
// here the log display the correct value I need
Log.i("Log", string);
}
onCancelled() ...
}
});
return string; // HERE THE VALUE IS NULL!!!!
As written above the log show the correct value, but when I try to return it its value becomes null.
It's within the inner block, that's why it happens
Move the return function to the inside of the block so it will show the correct value
First try moving the return string; inside the method body, then if it doesn't help read below.
addListenerForSingleValueEvent() executes onDataChange method immediately and after executing that method once, it stops listening to the reference location it is attached to.
So instead use addValueEventListener(), which keeps listening to the query or database reference it is attached to as mentioned here Read and Write Data on Android
Here is another useful information from the official documentation:
The listener receives a DataSnapshot that contains the data at the
specified location in the database at the time of the event. Calling
getValue() on a snapshot returns the Java object representation of the
data. If no data exists at the location, calling getValue() returns
null.
In this example, ValueEventListener also defines the onCancelled()
method that is called if the read is canceled. For example, a read can
be canceled if the client doesn't have permission to read from a
Firebase database location. This method is passed a DatabaseError
object indicating why the failure occurred.
Related
This question already has an answer here:
getContactsFromFirebase() method return an empty list
(1 answer)
Closed 4 years ago.
I'm cycling through some children in firebase to see if the value of a key exists, and in my addListenerForSingleValueEvent function the key is found and a global boolean is set to true. However, after the function, the variable is set as false so the program does not enter the second if statement.
referenceClasses.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
if (snapshot.getKey().compareTo(combinedString) == 0) {
found = true;
break;
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) { }
});
if(found) {
//...
}
I know found is set to true within the addListenerForSingleValueEvent through various inputs to my database. the boolean is instantiated as
boolean found;
globally, before any other functions. I even tried to implement two functions, one which sets the boolean and another which returns it but I ended up with the same results of the boolean being true within addListenerForSingleValueEvent and false in the if statement. Any ideas?
This is happening because the firebase calls are asynchronous and as a result your program might be hitting the if block before it even enters the onDataChange() method. To see if this is the case, you could put a breakpoint inside onDataChange and a breakpoint on the if(found) line and see which one gets executed first.
If all you are trying to do is execute some code once found is set to true, then you should just move the whole if block inside onDataChange.
Hopefully this helps!
I am trying to use runTransaction() of Firebase database but it is not working. Here is the code I am using.
numQuestionRef.runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(MutableData mutableData) {
String numQuestions = (String) mutableData.getValue();
long value = Long.parseLong(numQuestions, 16);
value++;
String incHex = Long.toHexString(value);
mutableData.setValue(incHex);
return Transaction.success(mutableData);
}
#Override
public void onComplete(FirebaseError firebaseError, boolean b, DataSnapshot dataSnapshot) {
}
});
This code is activated when I press a button within my app. When I press the button for the first time since launching the app, my database does not change. But when I press the button the second time since launching the app, it updates it to the next number. I don't understand what it wrong or why it only does it on the second button press.
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.
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.
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.
The Firebase client then sends both the assumed current value and the new value to the server.
If the actual stored value is the same as the assumed current value, the Firebase server writes the new value you specified.
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.
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().
This question already has answers here:
Setting variable inside onDataChange in Firebase (singleValue Listener)
(3 answers)
Closed 5 years ago.
I'm using firebase in my project and i'm trying to figure out how to fix the next issue for few hours already without success,
I have the next code:
// gameIDperm is set as 0 as default
public void GenerateID(){
ref2.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
if(snapshot.hasChild(gameIDperm))
{
gameIDperm = Integer.toString(Integer.parseInt(gameIDperm)+1);
Log.d("ID XXXX" , gameIDperm); // Here it says the right number
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Log.d("ID YYYYYYYY" , gameIDperm); // Here it says gameIDperm is 0 again
}
How can i make the variable being saved in the current function and not being reset again to default?
Hope you can help!
The code inside of the firebase listener is a callback, it will be called at some point in the future but it is not specified when that will happen.
So what happens is:
You call ref2.addListenerForSingleValueEvent(..)
You execute Log.d("ID YYYYYYYY" , gameIDperm);, at this point the variable has not been changed yet.
Firebase invokes onDataChange(..) at a later date, changing the variable.
You execute Log.d("ID XXXX" , gameIDperm);
In such an asynchronous execution you cannot rely on the order of the code to tell you when things get executed.
In addition you are using the variable gameIDperm to look up a child of the firebase reference, then rewriting that variable with the contents. This is probably not correct.
I have the following json tree in my firebase app
--ashWoYViS3SbHtBhLpvStRleBl13
----items
-------- -KxDDW1FYMUOxea5w5ii
------------- description: "gggh"
------------- name: "gggh"
ashWoYViS3SbHtBhLpvStRleBl13 is the userId, obtaineid with FirebaseAuth.getInstance().getUser().getUid();
And -KxDDW1FYMUOxea5w5ii is the key for an item, obtained with the push function before inserting the item in the json tree.
There are more items under the items node, this is only a sample.
Then I want to read all the items to show them in a list in my app. I do the following:
ValueEventListener listener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Item> items= utils.convertChildrenToList(dataSnapshot, Item.class);
getView().setData(customContexts);
getView().showContent();
}
#Override
public void onCancelled(DatabaseError databaseError) {
getView().showError(databaseError.toException(), true);
}
};
Query query = database.getReference("/ashWoYViS3SbHtBhLpvStRleBl13/items")
.orderByKey();
query.addValueEventListener(listener);
At this moment there are 5 items in the list, and after setting the listener with addValueEventListener, I expect to receive the result in onDataChanged only once. What really happens is that I receive infinite calls to onDataChanged every few seconds. The first time the snapshot has the 5 items. The second time the snapshot is empty (null). The third time the snapshot has again the 5 items, and so on, in an infinite loop.
The database is not being updated, because of that I don't understand why I'm becoming more than one callback in onDataChanged. The data is always there, and I don't understand also why the snapshot's value is sometimes null
If I use addListenerForSingleValueEvent instead, then I receive only one result in the callback "onDataChanged". Sometimes the snapshot value is null, sometimes the snapshot has the 5 elements. In any case, it does not solve my problem.
I tried with many versions of the Firebase sdk, from v11.0.2 to firebase 11.4.2, and it happens in all the versions.
The only way to solve the problem I found, is the following.
Instead of registering the listener for the path
"/ashWoYViS3SbHtBhLpvStRleBl13/items", I register a listener for the path
"/some_prefix/ashWoYViS3SbHtBhLpvStRleBl13/items" (and obviously, I save the data using the same prefix too).
Then all works as expected, that is, I receive only on result in the callback "onDataChanged". The snapshot is not null, and I receive the next callbacks only when the data under the items node is really changed.
Or if I use addListenerForSingleValueEvent, then I receive only one callback with all the elements in the node "items".
May you say me what I'm doing wrong here? (because I don't want to use the prefix before the user id).
Thanks in advance.
Every time you want to make a query make the fetched false to make sure that onDatachange read the method but when the method inside the onDataChange want to call onDataChange with accident can't have access because your fetched is true then.
For exemple when you make insertion in onDataChange the method will call them self other time without you calling them.
Boolean fetched = false;
ValueEventListener listener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (fetched == false) {
fetched = true;
List<Item> items = utils.convertChildrenToList(dataSnapshot, Item.class);
getView().setData(customContexts);
getView().showContent();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
getView().showError(databaseError.toException(), true);
}
};
Query query = database.getReference("/ashWoYViS3SbHtBhLpvStRleBl13/items")
.orderByKey();
fetched=false;
query.addValueEventListener(listener);
I have a firebase repository, and the data is structured like the following:
I am writing java code and i just want to get the value of "listname". HEre is what i do:
Firebase f = new Firebase("https://marketlist.firebaseio.com/sharedlists/list1/listname");
and then, when i look at member functions of my firebase object f, isee that there is a getName() function that returns listname, which is "list1", but there is no getValue() function here. Also, i tried
Query q = f.startAt("list1").endAt("list1");
but again, i cannot get the value. Can anybody help me with this?
Thanks
Firebase's logic is that data may change over time. So instead of exposing a value on the Firebase reference, you need to listen for changes like this:
f.on('value', function(snapshot) {
var val = snapshot.val();
});
Inside this callback function, val will now have list1 as its value.
If/when the value of listname changes, the callback will be called again and val will have the new value.
Update
I had missed that you use Java, so the above example is for JavaScript.
In Java the mechanism is very similar, but syntactically different:
f.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
String val = (String) snapshot.getValue());
}
#Override public void onCancelled() { }
});
So you attach a listener through addValueEventListener. Then the onDataChange method is invoked immediately for the initial value and whenever the referenced value changes.