Firebase - Get firebase data synchronously in for loop? - java

I'm trying to download firebase data in for loop then notify RecyclerView adapter. But since firebase runs async task. I'm not able to do that. How to force firebase to run synchronously or how to know all firebase data is downloaded.
Example code:
for(int i=0;i<list.size();i++){
FirebaseDatabase.getInstance().getReference().child(list.get(i)).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Post post = dataSnapshot.getValue(Post.class);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
//When all data is downloaded
adapter.notifyDataSetChanged();

There is no way to force Firebase to read the data synchronously.
But if all you want to do is know when all data has been loaded, you can keep a simple counter of the number of items that successfully loaded:
int completedCount = 0;
for(int i=0;i<list.size();i++){
FirebaseDatabase.getInstance().getReference().child(list.get(i)).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Post post = dataSnapshot.getValue(Post.class);
completedCount = completedCount + 1;
if (completedCount == list.size()) {
adapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
}

Related

Get a specific nested child and count it

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!
}
});

My Firebase is not retrieving data from Firebase Database

I have seen many other similar questions and also tried their method but still its not working.
My getFirebase function on a Click Listener :
private void getFirebase() {
firebaseDatabase = FirebaseDatabase.getInstance();
reference = firebaseDatabase.getReference().child("Questions/m1");
List<String> list = new ArrayList<>();
Log.d("QuizFragment", "getfirebase");
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d("QuizFragment", " Snapshots");
list.add(dataSnapshot.getValue().toString());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("QuizFragment", "error " + databaseError.toString());
}
});
Log.d("QuizFragment","debug");
}
My Logcat is showing getFirebase and then directly debug message.
I have seen many answer to wait for execution of SingleEvent but I have waited for many time still its not showing. Note : I am running app on emulator
addListenerForSingleValueEvent will get the data from the local disk cache.If you don't have any data in your cache you won't get any data.i believe that's why you could not get into onDataChange(). so first get data at least once like this
firebaseDatabase.getReference().child("Questions/m1")
.get()
.addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if (!task.isSuccessful()) {
Log.e("firebase", "Error getting data", task.getException());
}
else {
Log.d("firebase", String.valueOf(task.getResult().getValue()));
}
}
});
//then use cache data.
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d("QuizFragment", " Snapshots");
list.add(dataSnapshot.getValue().toString());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("QuizFragment", "error " + databaseError.toString());
}
});

Detect value change with firebase ValueEventListener

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
}
});

check if data exist in Firebase Database

I want to check if data already exists in firebase database
this is my code to show data from firebase database :
databaseCars.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
carsList.clear();
for(DataSnapshot carSnapshot : dataSnapshot.getChildren()){
Cars cars = carSnapshot.getValue(Cars.class);
carsList.add(cars);
}
ArrayAdapter adapter = new CarsList(listView_Car.this,carsList);
listViewCars.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Can you try adding
if (dataSnapshot.hasChild(dataToAdd)) {
// data exist
}
Doc: https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot.html#haschild

how to get string array from firebase realtime database

databaseReference = FirebaseDatabase.getInstance().getReference("/sample");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Log.d(TAG, "onDataChange: dataSnapshot "+dataSnapshot.getValue());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
I'm new to android app development and firebase as well. i m fetching data from sample node and getting DataSnapshot value like below.
{size=[Small, Large, Ex-Large], type=[Type 1, Type 2], color=[Red, Green, Blue], category=[T-Shirt, Jeans, Sweater]}
need some expect help, any suggestion will greatly appreciated.
Thanks
To retrieve values separately, you can use a code like this:
databaseReference.child("category").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (int i=0;i<3;i++) {
// category is an ArrayList you can declare above
category.add(dataSnapshot.child(String.valueOf(i)).getValue(String.class));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) { // Do something for this
}
});
Similarly you can add values of other nodes in your other ArrayLists, just by changing the value of Childs in this code.
Firebase has no native support for arrays. If you store an array, it really gets stored as an "object" with integers as the key names.
// we send this
['hello', 'world']
// Firebase stores this
{0: 'hello', 1: 'world'}
Best Practices: Arrays in Firebase
// TRY THIS
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
youNameArray = new ArrayList<>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
String data = snapshot.getValue(String.class);
youNameArray.add(data);
}
Log.v("asdf", "First data : " + youNameArray.get(0));
}
Something like this:
databaseReference = FirebaseDatabase.getInstance().getReference("/sample");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot sampleSnapshot: dataSnapshot.getChildren()) {
Log.d(TAG, "onDataChange: sampleSnapshot "+sampleSnapshot.getKey()+" = "+sampleSnapshot.getValue());
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
The difference is that in my answer I loop over dataSnapshot.getChildren() to get each individual sample snapshot. The sampleSnapshot.getValue() call should return a List.
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference refence = database.getReference();
refence.addValueEventListener(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot snapshot) {
// TODO Auto-generated method stub
ArrayList array= new ArrayList<>();
for (DataSnapshot ds : snapshot.getChildren()){
String data = ds.getValue().toString();
array.add(data);
}
System.out.println(array);
}
#Override
public void onCancelled(DatabaseError error) {
// TODO Auto-generated method stub
}
});
In my case String.class does not work instead .toString method works
String data = ds.getValue().toString();

Categories