I am trying to detect value change from my Firebase Database. Here is my code for initializing the ValueEventListener:
valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
try {
String customerLocation = String.valueOf(dataSnapshot.getValue());
Point customerPoint = locationFounder.getPoint(customerLocation);
if (customerPoint != null) {
databaseReference.child("isActive").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
boolean isActive = Boolean.valueOf(String.valueOf(dataSnapshot.getValue()));
displayPopUp(isActive, customerPoint, customerLocation);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
} catch (Exception e) {
Log.d("Listener",e.toString());
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
destinationReference.addValueEventListener(valueEventListener);
Problem occurs when I want to call this listener in my activity. I've been trying with this:
destinationListener.getValueEventListener().onDataChange(REQUIRED_SNAPSHOT);
I do not know how can I get datasnapshot which is required for onDataChange. I would like to get this work with ValueEventListener, not ChildEventListener, if possible. However, I am not pretty sure that this is the right way of trying to detect value change. If there is any other way that will work properly, I'd like to know about it.
There is nothing built to the Firebase Realtime Database to tell you what specific data under the snapshot has changed in the onDataChange method.
If you want to know what specific property has change, you'll need to:
Keep the snapshot that you get in onDataChange in a field.
When onDataChange gets called, compare the data in the new snapshot with the data in the field.
Say that you have a reference on a node in your JSON, and under that node is a status property, and you want to both listen to the entire node, and detect if the status has changed.
You'd do that with something like:
// Add a field to your class to keep the latest snapshot
DataSnapshot previousSnapshot;
// Then add your listener
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
bool wasActive = false;
if (previousSnapshot != null && previousSnapshot.child("status").exists()) {
wasActive = dataSnapshot.child("status").getValue(Boolean.class);
}
boolean isActive = dataSnapshot.child("status").getValue(Boolean.class);
if (isActive <> wasActive) {
... the user's status changed
}
previousSnapshot = dataSnapshot;
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // never ignore errors
}
});
Related
I registered such a method of receiving from folders in firebase, first I tried it in SwipeCard, it didn’t appear there, so I did the same test in a simple imageview and the data didn’t appear either. The link opens the photo. What is wrong in my code change and how to fix it? Thanks in advance
private void getUsermenwomInfo()
{
DatabaseReference reference= FirebaseDatabase.getInstance().getReference()
.child("User");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists()&&snapshot.getChildrenCount()>0)
{
String name=snapshot.child("name").getValue().toString();
nameusercard.setText(name);
if (snapshot.hasChild("image")) {
String image = snapshot.child("image").getValue().toString();
Picasso.get().load(image).into(imageosnovnoe);
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
}
I making an Attendance App.
In the app there is a function to know how many event an users already attend and what event they attend.
What i want is something like this (i dont know if it work or there is a better way):
private void fetchSpecificEvent() {
//Fetch event that user already attend
FirebaseRecyclerOptions<ModelEvent> options = new FirebaseRecyclerOptions.Builder<ModelEvent>()
.setQuery(referenceForSpecificEvent, snapshot -> new ModelEvent(
Objects.requireNonNull(snapshot.child("eventID").getValue()).toString(),
...
...
...
)
.build();
...
}
private void getAttendanceCount(){
//Get how many event user already attend
referenceForCount.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
attendanceCount = (int) snapshot.getChildrenCount();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
The main problem is i dont know what reference i use on: referenceForSpecificEvent and referenceForCount
This the JSON:
This the full JSON : https://pastebin.com/k65jhMUC
Sorry for the title, i dont know the keyword for it.
I found the way to do it. Probably not the best (because i cant really explain what i want) but it works.
reference = FirebaseDatabase.getInstance().getReference().child("Attendance");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
for (DataSnapshot eventSnapshot: dataSnapshot.getChildren()) {
//Get Event ID
Log.i(TAG, eventSnapshot.getKey());
for (DataSnapshot userSnapshot: dataSnapshot.child(Objects.requireNonNull(eventSnapshot.getKey())).getChildren()) {
//Get User ID
//Log.i(TAG, userSnapshot.getKey());
if(Objects.equals(userSnapshot.getKey(), stringEmail)){
intCount++;
listEvent.add(eventSnapshot.getKey());
}
}
}
}
else{
Log.i(TAG, "No Value Found");
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Log.d(TAG, error.getMessage()); //Don't ignore errors!
}
});
I want to read Music_ID of the group with Playlist_ID of 2 in firebase.
The following error occurs.
java.lang.NullPointerException: println needs a message
This is my firebase realtime database.
And this is my code.
database = FirebaseDatabase.getInstance();
storage = FirebaseStorage.getInstance();
dref = FirebaseDatabase.getInstance().getReference();
private void Startplaylist(String mood) {
DatabaseReference plist = dref.child("Playlist");
plist.orderByChild("Playlist_ID").equalTo(2).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
// Log.i("Value", dataSnapshot.getValue().toString());
String music_id = dataSnapshot.child("Music_ID").getValue(String.class);
Log.i("Value_id", music_id);
str_musictitle.setText(music_id);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
An alarm pops up that an error occurs in this part.
Log.i("Value_id", music_id);
I think "music_id" is not being read.
I tried to change part
String music_id = dataSnapshot.child("Music_ID").getValue(String.class);
to String music_ids = dataSnapshot.child("Music_ID").getValue().toString(); and run it, but I couldn't get the desired result.
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.
The code in your onDataChange will need to handle this list by looping over dataSnapshot.getChildren(). Something like this:
DatabaseReference plist = dref.child("Playlist");
plist.orderByChild("Playlist_ID").equalTo(2).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot: dataSnapshot.getChildren()) { // 👈 Loop over results
String music_id = snapshot.child("Music_ID").getValue(String.class); // 👈 Get value for this result
Log.i("Value_id", music_id);
str_musictitle.setText(music_id);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException(); // 👈 Never ignore possible errors
}
});
This is my code. I need to exit from for loop while data snapshot exists or not. I have tried with a listener interface that will invoke a call back when a data snapshot found or not. However, this listener is invoking only after all iterations. I need to exit the loop immediately. I even tried saving a boolean value in a shared preference and retrieve that value and check if it is true then only run for loop. But that approach is also not working. What is happening here, for loop is iterating through all users then only I'm getting the result from firebase background task.
private void createBranchAndAddUser(final String userKey) {
// Getting the referring user from DB
reference.child("User").orderByChild("uid").equalTo(referredBy)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot dst : dataSnapshot.getChildren()) {
referrerKey = dst.getKey(); // Got referring user firebase key
// Getting referring user branches.
reference.child("User").child(referrerKey).child("Branch")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// Branch found under referrer.
if (dataSnapshot.getChildrenCount() == 1) {
// One branch found under referrer. Adding one more under referrer.
Branch branch = new Branch();
branch.setUser_key(userKey);
reference.child("User").child(referrerKey).child("Branch").push().setValue(branch);
} else { // Two branch found under referring user. So moving to the next step.
// GETTING COMPLETE LIST OF USERS WHO ARE REFERRED BY REFERRING USER. (2: Step -> 2)
reference.child("User").orderByChild("referredBy").equalTo(referredBy).
addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull final DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// THIS IS THE LOOP I WANT ESCAPE.
for (DataSnapshot ds : dataSnapshot.getChildren()) {
User user = ds.getValue(User.class); // Got all users under referrer.
final String childUserKey = ds.getKey(); // Got firebase key of first child user under referrer.
Log.e(TAG, "isBranch Created " + isBranchCreated);
assert childUserKey != null;
reference.child("User").child(childUserKey).child("Branch")// getting branches of child user. (2: Step -> 3)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
if (dataSnapshot.getChildrenCount() == 1) {
// One branch found under child user.
Branch branch = new Branch();
branch.setUser_key(userKey);
reference.child("User").child(childUserKey).child("Branch").push().setValue(branch);
// need break the loop here, escape from the loop
isBranchCreated = "YES";
}
} else {
Branch branch = new Branch();
branch.setUser_key(userKey);
reference.child("User").child(childUserKey).child("Branch").push().setValue(branch);
// or break the loop here and escape from the loop.
isBranchCreated = "YES";
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.e(TAG, "onCancelled: " + databaseError.getMessage());
}
});
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.e(TAG, "onCancelled: " + databaseError.getMessage());
}
});
}
} else {
// No branch found under referrer.
Branch branch = new Branch();
branch.setUser_key(userKey);
reference.child("User").child(referrerKey).child("Branch").push().setValue(branch);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.e(TAG, "onCancelled: " + databaseError.getMessage());
}
});
}
I'm running into some trouble figuring out how to get the number of items/children in my Firebase real-time database for my app to use as an int value.
Check the image below:
So as you can see above, I have 2 children of images_list.
What I want to do is: get the number of items/children of images_list returned to my app, which would obviously equal 2 initially, and have this number expand whenever I add more items/children.
So my question is, what code do I implement to grab the number of children in this database? And how could I then convert this number into an int value? I've already experimented with differing methods, but I haven't found a solution as of yet.
I hope that made sense. Thanks so much for any of your assistance!
Code solution down here; I had to move most of this code from my RecyclerView Adapter into my MainActivity for it to work
Interface
public interface FirebaseCallback {
void onCallback(List<String> list);
}
readData method
private void readData(final FirebaseCallback firebaseCallback) {
mDatabaseImagesRef = FirebaseDatabase.getInstance().getReference("images_list");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String imageItems = ds.getValue(String.class);
imageList.add(imageItems);
}
firebaseCallback.onCallback(imageList);
Log.i("imageList.size() is: ", String.valueOf(imageList.size()));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.i(LOG_TAG, databaseError.getMessage());
}
};
mDatabaseImagesRef.addListenerForSingleValueEvent(valueEventListener);
}
called in onCreate()
readData(new FirebaseCallback() {
#Override
public void onCallback(List<String> list) {
mImageAdapter.notifyDataSetChanged();
}
});
getItemCount() in RecyclerViewAdapter
#Override
public int getItemCount() {
return imagesList.size();
}
To count the all the children beneath images_list node, please use the following lines of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference imagesListRef = rootRef.child("images_list");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int count = (int) dataSnapshot.getChildrenCount(); //Cast long to int
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, databaseError.getMessage());
}
};
imagesListRef.addListenerForSingleValueEvent(valueEventListener);
how could I then convert this number into an int value?
According to the official documentation, getChildrenCount() method returns a long and not an int. So you need to cast that primitive long to an int.
how to extract count from this block of code so that it can be referenced and used outside this code as well?
You cannot simply create the count variable as a global variable and use it outside the onDataChange() method because it will always be 0 due the asynchronous behaviour of this method. This means that if try to use its result outside this method, the data hasn't finished loading yet from the database and that's why is not accessible. With other words, your count will always be 0.
A quick solve for this problem would be to use the value of your count variable only inside the onDataChange() method, otherwise I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.
try this
userReference = FirebaseDatabase.getInstance().getReference("images_list");
userReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
num = dataSnapshot.getChildrenCount();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
mRef= FirebaseDatabase.getInstance().getReference("images_list");
on your "onDataChange" method inside the listener , use getChildrenCount() to get the number of images, you can iterate those children using i loop , Exmeple :
mRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int count = dataSnapshot.getChildrenCount();
// here you get your images number
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String key = ds.getKey()
// and here you get the key
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Try this code:
public void onDataChange(#NonNull DataSnapshot snap) {
int count = (int) snap.getChildrenCount();
//shows the number of items
}