Reputation: 930
I have a list in java android:
List<FirebaseData> GetListMap(String data){
final List<FirebaseData> Elements = new ArrayList<>();
FirebaseDatabase database = FirebaseDatabase.getInstance();
mShiftReference = database.getReference("Map/Data/").child(data);
mListener = mShiftReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot child: dataSnapshot.getChildren()) {
Elements.add(child.getValue(FirebaseData.class));
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
// Failed to read value
Log.w("data", "Failed to read value.", error.toException());
}
});
return Elements;
}
When i try to exctract the size of the array it returns 0, for example:
int size = GetListMap("2019-06-24").size();
Or i can't exctract any property.
Any idea what i'm doing wrong.
Upvotes: 0
Views: 119
Reputation: 1771
You are returning the list before firebase has finished adding everything. You want to create an interface method for the function.
in the class create an interface:
public interface Complete{
void taskCompleted(List<FirebaseData> list);
}
then assign it to your method (now returns void as the interface will be producing the result):
public void GetListMap(String data, Complete completeListener){
. . . .
mListener = mShiftReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot child: dataSnapshot.getChildren()) {
Elements.add(child.getValue(FirebaseData.class));
}
completeListener.taskComplete(Elements);
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
completeListener.taskComplete(null);
}
});
}
To use method:
GetListMap("data", new Complete() {
@Override
public void taskCompleted(List<FirebaseData> list) {
//do what you want with the list object
}
});
Upvotes: 1
Reputation: 2321
First of all your GetListMap
method contains firebase database call which of-course asynchronous call. Means you are getting data on separate thread. So the line below this calls execute before firebase process query response. So it is not possible to get returned value from method which contains asynchronous functions.
So to get exact what you want, you will have to wait for query response.
Refer below code to achieve what you want.
// Avoiding return type with this method.
void GetListMap(String data){
final List<FirebaseData> Elements = new ArrayList<>();
FirebaseDatabase database = FirebaseDatabase.getInstance();
mShiftReference = database.getReference("Map/Data/").child(data);
mListener = mShiftReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot child: dataSnapshot.getChildren()) {
Elements.add(child.getValue(FirebaseData.class));
}
// Use below method to update data inside your views.
// This method will only called once firebase query return response.
updateUI(Elements);
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
// Failed to read value
Log.w("data", "Failed to read value.", error.toException());
}
});
// Now this method is void so need to return any value.
//return Elements;
}
Example of updateUI(...)
method.
void updateUI(List<FirebaseData> elements) {
int size = elements.size();
}
Upvotes: 0
Reputation: 826
You're returning your Elements collection before it actually gets data from your Firebase Database due to the asynchronous nature of your listener.
You'd have to define a callback if you want to get an update after your async code is done
List<FirebaseData> GetListMap(String data){
final List<FirebaseData> Elements = new ArrayList<>();
FirebaseDatabase database = FirebaseDatabase.getInstance();
mShiftReference = database.getReference("Map/Data/").child(data);
mListener = mShiftReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
System.out.println("About to fill Elements");
for (DataSnapshot child: dataSnapshot.getChildren()) {
Elements.add(child.getValue(FirebaseData.class));
}
System.out.println("Elements is filled");
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
// Failed to read value
Log.w("data", "Failed to read value.", error.toException());
}
});
System.out.println("Returning Elements with size: " + Elements.size());
return Elements;
}
int x = GetListMap("...").size();
System.out.println("x: +" x);
``
That code would result in following output:
Btw please use camelCase for your methods and variables whenever you are developing in Java
Upvotes: 3
Reputation: 5592
First, I assume you mean int size = GetListMap("2019-06-24").size();
(size at the end).
Second, you are assigning a list to the returned value, it's an empty list at this moment. Then you attach a listener that waits for an event (data change), if that happens, then and only then it will add an element to the list.
Basically, your list is always gonna be empty, unless the data change events occur. You need to trigger an event and then check the list, it should change it's size.
Upvotes: 3