I am trying to return every dataSnapshot.getKey() in onAddchild to the main method to be used and back to this method to add a new child again, here is my code
private String NameSub(DataSnapshot dataSnapshot) {
RootRef.child(dataSnapshot.getKey()).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
NameSub = dataSnapshot.getKey();
Log.i("ttttttttttttttttttttt20", NameSub);
return;
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
Log.i("ttttttttttttttttttttt21", String.valueOf(NameSub));
return NameSub;
}
I'm logging to trace the code and it's giving me Log"ttttttttttttttttttttt21" beftore Log"ttttttttttttttttttttt20". Also, giving me null value towards the 21 Logs.
How is it that the code is working, but it is printing Log 21 before Log 20? How can I fix that?
NB: I'm receiving no null value of dataSnapshot from another Firebase method
new ChildEventListener() { ... } is a callback.
When your function is called, this is what happens.
private String NameSub(DataSnapshot dataSnapshot) {
RootRef.child(dataSnapshot.getKey()).addChildEventListener(new ChildEventListener() { ... });
Log.i("ttttttttttttttttttttt21", String.valueOf(NameSub));
return NameSub;
}
So your function returns a null value.
Later whenever a child is added to your firebase realtime database, onChildAdded(...) is called.
This happens asynchronously. This updates the NameSub value.
So your code is printing Log 21 before Log 20.
Related
My problem is the same with title,firebase onchildadded() returns same data 3 times in listview.I tried many things but still couldnt found solution.
My code is there;
public void ReceiveMessages(){
childEventListener = message_dbref.child(user_id).child(user2_id).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Message message = dataSnapshot.getValue(Message.class);
message_dbref.removeEventListener(childEventListener);
user_dbref.removeEventListener(valueEventListener);
messageArrayList.add(message);
messageAdapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
So you should not be using a childEventListener because it fires whenever any child of the parent node changes.
You can check if you're updating other children of the parent node on which your childEventListener is set, along with others. That must be the case, for it to fire 3 times.
So you should rather focus on using a singleValueEventListener or a valueEventListener on the same reference you're using right now.
Read more about childEventListeners here.
Understand more about reading and writing on Firebase here.
This question already has an answer here:
ArrayList not updating inside onChildAdded function
(1 answer)
Closed 4 years ago.
I want to get the whole value(0~5) from destinations
This is part of json data in realtime database
{"results" : [{
"destin_num" : 6,
"destinations" : [ "asdf", "qwwee", "zzzxcv11", "jkkk", "lkjhhg", "zxcvb" ],
"name" : "asdfasdfff",
"order" : 2,
"required_time" : "6hours" }]}
the value I want to put in the String List , I use ChildEventListener() to add the value into List, but the value can't put into the List after finish the ChildEventListener().There will be nothing in List direction How to get the values?
List<String> direction=new ArrayList<String>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
DatabaseReference reference_contacts = FirebaseDatabase.getInstance().getReference("results").child("1").child("destinations");
reference_contacts.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String data=dataSnapshot.getValue().toString();
direction.add(data);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
for(int i=0;i<direction.size();i++){
Log.e("Get data",direction.get(i));
}
}
It's because data is loaded from Firebase asynchronously. Your for loop printing the values is actually run before onChildAdded ever gets called. It's easiest to see this by adding some logging:
Log.i("Firebase", "Before adding listener");
reference_contacts.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.i("Firebase", "In onChildAdded");
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) { }
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) { }
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) { }
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
Log.i("Firebase", "After adding listener");
When you run this code it prints:
Before adding listener
After adding listener
In onChildAdded
That is probably not the order you expected. But is completely explains why the direction list is empty when you print it, the data hasn't been loaded yet, so onChildAdded has never been invoked.
The solution is typically to add the code that requires the data into the onChildAdded method:
So:
reference_contacts.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String data=dataSnapshot.getValue().toString();
direction.add(data);
Log.i("Got data",direction);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
If you only want to show the data once everything is loaded, you can use a ValueEventListener instead:
reference_contacts.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot: snapshot.getChildren()) {
String data=dataSnapshot.getValue(String.class);
direction.add(data);
}
for(int i=0;i<direction.size();i++){
Log.e("Get data",direction.get(i));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
Note that this is an incredibly common source of confusion for developers new to Firebase (and asynchronous APIs in general). I highly recommend studying some of the answers to some of these previous questions about the topic:
Setting Singleton property value in Firebase Listener
getContactsFromFirebase() method return an empty list (which also shows how to define a custom interface to allow the code that requires the data to be outside onChildAdded/onDataChange.
can't get values out of ondatachange method
ArrayList not updating inside onChildAdded function
I am trying to set my Firebase reference before my child listener kicks in and loads my data. I know onCreate is ahead of onResume but my code below seems to contradict it as my reference is still what I have set in my onResume(). It seems like what I set up in onCreate doesn't go before what I have in onCreate().
Why is that?
I am trying to read from a template in my database if another node doesn't have the user registered as a child yet.
Any hint would be appreciated.
p.s. I have logged out the references and the Log in OnResume() goes first as well.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.services_activity);
app = FirebaseApp.getInstance();
database = FirebaseDatabase.getInstance(app);
auth = FirebaseAuth.getInstance(app);
storage = FirebaseStorage.getInstance(app);
username = auth.getCurrentUser().getUid();
databaseRef = database.getReference("serv_hst");
servTempltRef = database.getReference("serv_tmplt");
databaseRef.child(username).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
//I am trying to set my reference that I will use in OnResume() ..!!
if (dataSnapshot.hasChildren()) {
servTempltRef = database.getReference("serv_hst");
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
protected void onResume() {
super.onResume();
servTempltRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
The code inside the onChildAdded() will be executed asynchronously only when the data will be downloaded from Firebase Database.
So, after that the execution flow will execute the line in which there is the .addChildEventListener() method, it will go ahead and will continue to execute the next lines...
In your case, the onCreate() has no other lines to be executed. So, due to the Activity lifecicle, the onResume() method will be executed without the data you need.
I am working in my app with Firebase and I tried to use onChildAdded() callback but I think I am doing something wrong because I get no response.
/**
* Constructor
*/
private FirebaseManager(Context context) {
Firebase.setAndroidContext(context);
Firebase.getDefaultConfig().setPersistenceEnabled(true);
mFirebaseRef = new Firebase(FIREBASE_URL);
}
public void checkUsers() {
Firebase checkRef = mFirebaseRef.child("/data/users/");
// Also tried
// Firebase checkRef = mFirebaseRef.child("data").child("users");
checkRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.d(TAG,"New child added");
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
In onCreate() of my MainActivity I authenticate the user and the call checkUsers(). After that I manually add a new user in database. But I get nothing in log.
This is the json structure:
What am I doing wrong?
I got it. There was a concurrency problem. I called checkUsers() in onCreate() of the MainActivity but it needs to be called in onAuthenticated(), because the user was authenticated after the method checkUsers() tried to set listeners.
I got a LOG about the failure of accessing database:
W/SyncTree: Listen at / failed: FirebaseError: Permission denied
but didn't seen it because I was following a specific TAG with logcat Search.
My data on Firebase like this:
"node": {
"node1": {
"value1": value,
"value2": value,
"subSubNode":{
//....values....//
},
},
"node2": { ... },
"node3": { ... }
//...and so on ..//
}
First: I want to get all data from Firebase and render to my tree so I used addListenerForSingleValueEvent() function.
Then: I used addChildEventListener() function to listen when a node or child change, remove or added...
private void getData(Query ref){
ref.addListenerForSingleValueEvent(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
**I render data on my tree here**
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
ref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.i(TAG, "onChildAdded");
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
Log.i(TAG, "onChildChanged");
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.i(TAG, "onChildRemoved");
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
Log.i(TAG, "onChildMoved");
}
#Override
public void onCancelled(FirebaseError firebaseError) {
Log.i(TAG, "onCancelled");
}
});
}
But onChildAdded() method in addChildEventListener() function is always run first. Any idea or solution for me? Do I use addChildEventListener() function on that position correct?
The methods in ChildEventListener fire for both initial data and for subsequent changes to that data.
Once you call addChildEventListener(), you will get a call to onChildAdded() for each existing child node. You can use these event to build the initial tree. After the initial data has been added, you will receive a calls to all onChild... methods as the data changes.
So don't register for addListenerForSingleValueEvent() and simply build the tree from the methods of ChildEventListener.
Alternatively if you want to separately handle the initial data, you can make use of one of the event guarantees that Firebase has:
Value events are always triggered last and are guaranteed to contain updates from any other events which occurred before that snapshot was taken.
boolean isInitialValueLoaded = false;
ref.addListenerForSingleValueEvent(new ValueEventListener(){
public void onDataChange(DataSnapshot dataSnapshot) {
**I render data on my tree here**
isInitialValueLoaded = true;
}
public void onCancelled(FirebaseError firebaseError) {
}
});
ref.addChildEventListener(new ChildEventListener() {
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (!isInitialValueLoaded) return;
Log.i(TAG, "onChildAdded");
}
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
if (!isInitialValueLoaded) return;
Log.i(TAG, "onChildChanged");
}
public void onChildRemoved(DataSnapshot dataSnapshot) {
if (!isInitialValueLoaded) return;
Log.i(TAG, "onChildRemoved");
}
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
if (!isInitialValueLoaded) return;
Log.i(TAG, "onChildMoved");
}
public void onCancelled(FirebaseError firebaseError) {
Log.i(TAG, "onCancelled");
}
});