I am working with Firebase for my Android app. I have successfully retrieved information in multiple places in my code using something like:
dbRef = new Firebase(Constants.URL_DB);
childRef = dbRef.child(Constants.KEY_CHILD);
objectRef = childRef.child(objectId);
// Log the URL to the object.
// This has been verified. The path is good.
Log.d("DEBUG", "To String: " + objectRef.toString());
childRef.addValueEventListener(new ValueEventListener()
#Override
public void onDataChange(DataSnapshot snapshot) {
Log.d("DEBUG", "Success");
}
#Override
public void onCancelled(FirebaseError firebaseError) {
Log.e("DEBUG", "Failure");
}
});
The exact same code has been use successfully in another activity but for some reason, it doesn't work in on particular activity (onDataChange is never called, neither is onCancelled). Could it be that The Firebase sessions in other activities are conflicting with this one? I have seen problems that could be resolved with:
Firebase.goOnline();
Firebase.goOffline();
Althought I am not sure I understand what those exactly do. Maybe it is because I somehow can't access a child added by push() with his id?
UPDATE:
I successfully wrote in the database at objectRef, but onDataChange() is still never called.
Ok I found what was causing the problem. I had an empty loop because I needed the information to continue and it somehow prevented the events from the database. I had something like this in the onCreate():
childRef.addValueEventListener(new ValueEventListener()
#Override
public void onDataChange(DataSnapshot snapshot) {
Log.d("DEBUG", "Success");
object = snapshot.getValue(MyObject.class);
}
#Override
public void onCancelled(FirebaseError firebaseError) {
Log.e("DEBUG", "Failure");
}
});
And I had the loop in the onResume():
while(object == null);
What I did to correct the issue was replacing the loop with:
if(object == null){
// Do stuff
}
And I added a call to onResume() in onDataChange()
Related
In the code below i get the number of children but i want to use it outside the onDataChange method.
mRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
DateStorage dateStorage = null;
for (DataSnapshot result : dataSnapshot.getChildren())
{
Log.e(result.getKey(),result.getChildrenCount() + "");
in[0] = result.getChildrenCount();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Can anyone help me?
Data is loaded from Firebase asynchronously. Your main code continues to run while the data is loading, and then when the data is available the onDataChange method is called. What that means is easiest to see if you add a few log statements:
Log.d("TAG", "Before attaching listener");
mRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
Log.d("TAG", "Got data");
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
Log.d("TAG", "After attaching listener");
When you run this code, it logs:
Before attaching listener
After attaching listener
Got data
This is probably not the order you expected, but is completely normal when calling asynchronous APIs. And it explains why you'll get the wrong value if you print it outside of the onDataChange().
The problem is not that you can't use the data outside of the onDataChange(), the problem is that you must ensure that onDataChange() has run before you use the data.
The simplest way to do that is to put all code that requires data from the database inside the onDataChange method. But you can also create your own callback interface, and pass that into the method where you load the data. For an example of both of these approaches, see my answer here: getContactsFromFirebase() method return an empty list
So I am using Firebase Realtime Database and I want to remove a listener as soon as a certain criteria is met. Here is my code:
final DatabaseReference forRequests = FirebaseDatabase.getInstance().getReference(Common.requests + "/" + FirebaseAuth.getInstance().getUid());
listenForRequests = forRequests.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
pickuprequest.riderUID = (String) dataSnapshot.child(Common.riderUID).getValue();
if (pickuprequest.riderUID != null) {
forRequests.removeEventListener(listenForRequests);
showRequestOnMap(forRequests);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("The read failed: " + databaseError.getCode());
}
});
}
listenForRequests is a global variable. Just wondering if this code will work, or if there are any better solutions to this as I feel like it is very hacky.
I can't really tell what exactly your condition is really trying to express, but if you want just a single value a single time from the database (without listening to its changes over time), you can simply use addListenerForSingleValueEvent() to get a single snapshot of a node in the database.
If you're waiting for a value to appear that wasn't previously there, and you want to stop listening at the time it appears, what you're doing is fine. But you might want to listen more closely to the child of interest instead of its parent.
Your code looks pretty idiomatic to me when you want to wait for a specific value.
In fact, the code in my gist on waiting for an initial value is pretty similar:
mListener = ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
if (snapshot.exists()) {
System.out.println("The value is now "+snapshot.getValue());
ref.removeEventListener(mListener);
}
}
...
I'm creating an Android app for the first time, I've got a simple Realtime Firebase Database with a couple of records in it. I have the following code;
public void onStart() {
super.onStart();
// Read from the database
databaseMatches.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot matchSnapshot : dataSnapshot.getChildren()) {
matches match = matchSnapshot.getValue(matches.class);
matchesList.add(match);
}
matchList adapter = new matchList (getActivity(), matchesList);
listViewMatch.setAdapter(adapter);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
});
If I put a breakpoint on the databaseMatches.addValueEventListener(new ValueEventListener() { it shows me that the database connection has been set and is returning the correct object (In my view).
The challenge I have is the part after, the break points for public void onDataChange nor onCancelled ever get hit. I'm lost here and not sure what might be the next step as it appears to be connecting, but I am not able to retrieve records.
I'm doing this in a fragment instead of a activity. Any help is appreciated.
Detecting Connection State
it is useful for your app to know when it is online or offline. Firebase Realtime Database provides a special location at /.info/connected which is updated every time the Firebase Realtime Database client's connection state changes. Here is an example: If you are not sure.
https://firebase.google.com/docs/database/android/offline-capabilities#section-connection-state
DatabaseReference connectedRef =
FirebaseDatabase.getInstance().getReference(".info/connected");
connectedRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
boolean connected = snapshot.getValue(Boolean.class);
if (connected) {
System.out.println("connected");
} else {
System.out.println("not connected");
}
}
#Override
public void onCancelled(DatabaseError error) {
System.err.println("Listener was cancelled");
}
Firebase also loads and synchronizes data asynchronously
see Setting Singleton property value in Firebase Listener
Thanks.
There must have been some strange caching issue as the following morning when I ran the exact same code, no problem. And I've not had a problem since.
I want to count elements in a firebase database, I have seen different topics and tried this code:
final Query dataQuery = myRef.equalTo(MainActivity.user.getUid()).getRef();
dataQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.e("ERROR",""+dataSnapshot.child(MainActivity.user.getUid()).getChildrenCount());
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "onCancelled", databaseError.toException());
}
});
Now, the value in log error is correct but, if I try to assign it in field, or static field is always 0 out of this method;
How can I use this value in other class?
You need to use a callback and call a method on the callback in your onDataChange. Then once that callback is returned you can continue with the rest of your logic.
You can see an example of that here:
https://github.com/Austin-Android/austin-feeds-me/blob/master/app/src/main/java/com/austindroids/austinfeedsme/data/firebase/FirebaseEventsDataSource.java#L40
fireBase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Event event = snapshot.getValue(Event.class);
events.add(event);
}
callback.onEventsLoaded(events);
}
#Override
public void onCancelled(DatabaseError firebaseError) {
}
});
You cannot simply take that value and use it outside onDataChange() method, because it will always be null. This is happening because this method has an asynchronous behaviour, which means that is called even before you are getting the data out from the database. A quick fix would be to use that value only inside onDataChange() method, or to dive into the asynchronous world and see the last part of my answer from this post.
I have been looking for a way to get one child object's data in Android Firebase.
I have found things like Firebase retrieve child Android. All the solutions are suggesting using a "ChildEventListener", however I need to get this data at this moment, not when it is moved, deleted, updated, etcetera.
My data is kept in https://.firebaseio.com/users//creation as a string. I figure there must be some simple way to access that without needing to do too much, because if I copy the exact URL to my browser, I can see the: 'creation: "2015/05/31 21:33:55"' right there in my "Firebase Forge Dashboard".
How can I access this without a listener?
Firebase listeners fire for both the initial data and any changes.
If you're looking to synchronize the data in a collection, use ChildEventListener. If you're looking to synchronize a single object, use ValueEventListener. Note that in both cases you're not "getting" the data. You're synchronizing it, which means that the callback may be invoked multiple times: for the initial data and whenever the data gets updated.
This is covered in Firebase's quickstart guide for Android. The relevant code and quote:
FirebaseRef.child("message").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
System.out.println(snapshot.getValue()); //prints "Do you have data? You'll love Firebase."
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
In the example above, the value event will fire once for the initial state of the data, and then again every time the value of that data changes.
Please spend a few moments to go through that quick start. It shouldn't take more than 15 minutes and it will save you from a lot of head scratching and questions. The Firebase Android Guide is probably a good next destination, for this question specifically: https://firebase.google.com/docs/database/android/read-and-write
You don't directly read a value. You can set it with .setValue(), but there is no .getValue() on the reference object.
You have to use a listener. If you just want to read the value once, you use ref.addListenerForSingleValueEvent().
Example:
Firebase ref = new Firebase("YOUR-URL-HERE/PATH/TO/YOUR/STUFF");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String value = (String) dataSnapshot.getValue();
// do your stuff here with value
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
Source: https://www.firebase.com/docs/android/guide/retrieving-data.html#section-reading-once
just fetch specific node data and its working perfect for me
mFirebaseInstance.getReference("yourNodeName").getRef().addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
Log.e(TAG, "======="+postSnapshot.child("email").getValue());
Log.e(TAG, "======="+postSnapshot.child("name").getValue());
}
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.e(TAG, "Failed to read app title value.", error.toException());
}
});
I store my data this way:
accountsTable ->
key1 -> account1
key2 -> account2
in order to get object data:
accountsDb = mDatabase.child("accountsTable");
accountsDb.child("some key").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
try{
Account account = snapshot.getChildren().iterator().next()
.getValue(Account.class);
} catch (Throwable e) {
MyLogger.error(this, "onCreate eror", e);
}
}
#Override public void onCancelled(DatabaseError error) { }
});