I am using Database Firebase in my project. I got a crazy confused with onChildAdded. I have code like this:
mEventListener = new ChildEventListener() {
#Override public void onChildAdded(#NonNull DataSnapshot dataSnapshot,
#Nullable String stringS) {
if (stringS != null
&& dataSnapshot.getKey()
!= null && !dataSnapshot.getKey().contains(stringS))
{
Log.e("=====", "onChildAdded: " + stringS +
" getKey: " + dataSnapshot.getKey());
}....
And I got logs here:
=====: onChildAdded: -LMsqXJTn5DoMZTELzuz getKey:
-LMsqXJVyXWZKqDizrCt
So what is the key of this "dataSnapshot" ???
In other cases I also got some opposite results, so it makes me really confused.
Added:
Some other DataSnapshot , they both are the same.
The onChildAdded gets two arguments:
The DataSnapshot that was just added
The key of the previous child after which this new data snapshot was added
So in your sample, the new snapshot has key -LMsqXJVyXWZKqDizrCt and it was added after -LMsqXJTn5DoMZTELzuz.
Also see the reference documentation for onChildAdded:
public abstract void onChildAdded (DataSnapshot snapshot, String previousChildName)
This method is triggered when a new child is added to the location to which this listener was added.
Parameters
snapshot - An immutable snapshot of the data at the new child location
previousChildName - The key name of sibling location ordered before the new child. This will be null for the first child node of a location.
Related
so I have a database where I search for products by barcodes.
I wanted to have a check to see if the products are in my database
mFirebaseInstance = FirebaseDatabase.getInstance();
mFirebaseDatabase = mFirebaseInstance.getReference("ProductData");
productId = mFirebaseDatabase.push().getKey();
public void searchProduct(String barcode){
Query barcodeQuery = mFirebaseDatabase.child("Products")
.orderByChild("barcode").equalTo(barcode);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String name = ds.child("name").getValue(String.class);
int price = ds.child("price").getValue(Integer.class);
int quantity = ds.child("quantity").getValue(Integer.class);
Log.d("DATABASE", name + "/" + price + "/" + quantity); /// The output that I get is this: Neopraxam/25/1 and Vazelina/250/1
That's how I search for the products by barcode.
searchProduct("123123123");
searchProduct("3232");
I have tried to add these methods to check if the value I'm trying to get is null:
if (ds.exists()){} OR
if (ds.getChildrenCount() != 0){}
But I have seen that it doesn't even enter in the loop if the value doesn't exist. So I'm assuming that It's coming from the query.
So, how can I check if the query returns a null value because I used the method .equalTo(barcode) so I suppose that it should return a true or a false value
Issue seem to be with onDataChange signature as it contains NonNull annotation. To execute onDataChange body even for DataSnapshot null value , update the signature as follows
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
.
.
.
}
Note: You should be using SingleValueEventListener instead of ValueEventListener
There is no way in which DataSnapshot's getChildren() method can return null:
Returns
True if the snapshot contains a non-null value, otherwise false
What you should use to solve the issue, is DataSnapshot's exists() method:
Returns
True if the snapshot contains a non-null value, otherwise false
So every time you perform a Query, check each item for existence using the above exists() method.
Besides that, your searchProduct() method can never return a value from the database. For more information, please see my answer from the following posT:
How to return DataSnapshot value as a result of a method?
I have a database that looks like this:
database
|
places
|
user1
| |___indoors: "yes"
| |___outdoors: "yes"
|
user2
|___indoors: "yes"
|___outdoors: "no"
When I do the following, I get all users places information as a single object (converted to String) with no problems:
ValueEventListener placesListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String locations = dataSnapshot.toString(); // I get the entire tree as String
}
}
//this is how I set the listener to changes
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
DatabaseReference reference = database.child("places");
reference.addValueEventListener(placesListener);
But, when I want only the indoors children, I get DataSnapshot {key = indoors, value = null}.
This is how I try to get only the indoors keys and values (almost the same, only adding extra .child("indoors"):
ValueEventListener placesListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String indoors = dataSnapshot.child("indoors").toString(); // I get value = null
}
}
// listener remains the same
The data contained in a DataSnapshot is relative, like a JSON tree. From the documentation on DataSnapshot#child():
Get a DataSnapshot for the location at the specified relative path. The relative path can either be a simple child key (e.g. 'fred') or a deeper slash-separated path (e.g. 'fred/name/first'). If the child location has no data, an empty DataSnapshot is returned.
In your example, there is no child named indoors directly under the places node. Instead, you have 2 children named user1 and user2 which each have a child named indoors. Therefore, in order to access one of the indoors children, you'll need to do something like:
dataSnapshot.child("user1").child("indoors").toString();
Alternatively, you can iterate through the children using:
for (DataSnapshot childSnapshot : dataSnapshot.getChildren()) {
Log.d(childSnapshot.getKey() + ": indoors=" + childSnapshot.child("indoors").toString());
}
I am seeing an confusing null pointer exception for only ONE of the children of my Firebase Realtime Database reference.
Query query = db.getReference("comments/" + eventId).orderByKey();
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This causes a null pointer exception.
Long date = dataSnapshot.child("date").getValue(Long.class);
// ...
}
// ...
}
I set a break-point and found that evaluating the following expression returns false.
dataSnapshot.child("date").exists();
The debugger displays this value for dataSnapshot:
DataSnapshot { key = c953b8fa-b569-4bc0-9302-3a9b34b22853, value = {0c2fd3e6-e9f1-43ce-a807-06b59e1b00bc={text=this comment is a comment., date=1515593659961, creatorId=gkbZMv2ThMh1xDwKyDP9oUtUIKi2, id=0c2fd3e6-e9f1-43ce-a807-06b59e1b00bc}} }
"date" is clearly present in the snapshot and all of the other children (e.g. "text", "creatorId", "id") are accessible. The only difference is that they are String values and "date" is a long.
How is this possible?
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
This means your code needs to handle the list by looping over DataSnapshot.getChildren():
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child: dataSnapshot.getChildren()) {
Long date = child.child("date").getValue(Long.class);
// ...
}
// ...
}
I'm having trouble getting from my Firebase database data to an android app and the Firebase listener and data snapshot documentations aren't really helping.
Say I have a database with the nodes structured as below:
Contacts-->
John : 1334255
May : 3345777
James : 5799862
Ford : 4574878
How can I directly retrieve the contacts from the nodes with the key and value both as strings , without having to cast them into some object(that's not the string object).
I want to be able to display the names(keys) as contact names and the numbers(their values) as Contact number.
Please try this code:
DatabaseReference contactsRef = FirebaseDatabase.getInstance().getReference().child("Contacts");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String name = ds.getKey();
String contactNumber = ds.getValue(String.class);
Log.d("TAG", name + ": " + contactNumber);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
contactsRef.addListenerForSingleValueEvent(eventListener);
Hope it helps.
tl;dr write them as something other than numbers
The values in your example are Long (integers). Assuming they're phone numbers, you'll probably want to store them as strings anyway. When you write a value to Firebase, it will infer the type and store it as one of the following:
String (will appear in quotes)
Long (whole number)
Double (decimal number)
Boolean (true or false without quotes)
Map<String, Object> (key with children)
List<Object> (key with children)
In your case, since you want to treat it as a String type when it's being read, just write it as a string:
If you're setting the values from client code, use the String type when you create the value.
If you're manually entering them from the dashboard, you can either wrap them in quotes or use non-numeric characters like the familiar format (123) 456-7890. Any value you type in that doesn't evaluate to a Long/Double/Boolean will be interpreted as a String.
My Firebase Database is like this
When the coding below was run:
String loc=(snapshot.child("loc").getvalue()).tostring();
The output I get has different sequence with the database:
Why is that so?
Firebase data is stored as JSON and is inherently unordered.
If you want to access the data in a specific order, you should specify an orderBy clause for your query and access the data using the snapshot's getChildren() method.
Say you want to log the items by ascending key:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getRef();
Query locations = rootRef.orderByKey();
locations.addListenerForSingleValueEvent(new ValueEventListener() {
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot locSnapshot: snapshot.getChildren()) {
System.out.println(locSnapshot.getKey() + ": " + locSnapshot.getValue(String.class));
}
}
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
});
This sample comes (modified) from the Firebase documentation on reading lists of data.
Frank beat me to my edit, check out his correct solution using orderBy....
You need to use forEach rather than the child method (or child.foreach)
Here is a snippet from the doc:
Because of the way JavaScript Objects work, the ordering of data in
the JavaScript Object returned by val() is not guaranteed to match the
ordering on the server nor the ordering of child_added events. That is
where forEach() comes in handy. It guarantees the children of a
DataSnapshot will be iterated in their query-order.
Source: https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#forEach