0

So I have been trying to download data from Firebase into an ArrayList:

 public void updateOnce(){
    animalList = new ArrayList<>();
    Query query = mDatabase.orderByChild("id");
    query.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            if (dataSnapshot.exists()) {
                for (DataSnapshot messageSnapshot: dataSnapshot.getChildren()) {
                    SpottedAnimal pet = messageSnapshot.getValue(SpottedAnimal.class);
                    animalList.add(pet);
                }
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
}

Debugger shows that the Object SpottedAnimal pet does get created and then inserted into the animalList that is a global ArrayList. But once I call the method:

public ArrayList<SpottedAnimal> getList(){
    return animalList;
}

The animalList comes out empty on the other side.

 FirebaseGetList() animalListHook = new FirebaseGetList(); 
 animalListHook.updateOnce();
 ArrayList<SpottedAnimal> animalList = animalListHook.getList();
Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
BryceSoker
  • 624
  • 1
  • 11
  • 29
  • Firebase API are asynchronous. Please read this blog to understand more about why this is. https://medium.com/google-developers/why-are-the-firebase-apis-asynchronous-e037a6654a93 – Doug Stevenson Apr 16 '18 at 23:21
  • Possible duplicate of [How to return dataSnapshot value as a result of a method?](https://stackoverflow.com/questions/47847694/how-to-return-datasnapshot-value-as-a-result-of-a-method) – Alex Mamo Apr 23 '18 at 16:34
  • Please see the duplicate to understand why you have this behaviour and how you can solve it. – Alex Mamo Apr 23 '18 at 16:35

1 Answers1

1

onDataChange() is an asynchronous call.
So you have to consume the list as the event that adds an Animal object is triggered.
The client class should implement a Observer interface or a similar thing and as you instantiate FirebaseGetList, you should pass this (the client object):

In the client class :

public interface Notifiable {
   void update();
}

public class ClientClass implements Notifiable {

    public void foo(){
      FirebaseGetList animalListHook = new FirebaseGetList(); 
      animalListHook.updateOnce(this);
      ArrayList<SpottedAnimal> animalList = animalListHook.getList();
   }

  @Override
  public void update(){
      // use the animalList here
  }
}

in FirebaseGetList :

 @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        if (dataSnapshot.exists()) {
            for (DataSnapshot messageSnapshot: dataSnapshot.getChildren()) {
                SpottedAnimal pet = messageSnapshot.getValue(SpottedAnimal.class);
                animalList.add(pet);                    
            }
            this.update(); // method to notify 
        }
    }

Note that using global variables is probably a design issue and should be corrected.
For example the update() method could pass the List of Animal as a parameter.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • Thank you, this got me an idea to what I should do, I'll try and get it to work and if it does work I'll mark it as done, it might take a while tho. – BryceSoker Apr 16 '18 at 19:19