0

I have an ArrayList on database and I have a function getArrayList that reference the database and returns the list. The problem is that I cannot save the arraylist because I get it from inner class.

*ArrayList waiting_list is defined outside

 private ArrayList<FirebaseUser> getWaitingList (String uid){
    database.child("books").child(""+itemNum+1)
    .addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot d:dataSnapshot.getChildren()){
                if(d.getKey().equals("waiting list"));
                        GenericTypeIndicator<ArrayList<FirebaseUser>> t = new GenericTypeIndicator<ArrayList<FirebaseUser>>() {};
                        waiting_list = d.getValue(t);// this is the problem
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
    return waiting_list; //I beleive that waiting_list is still null here
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Yael Pesso
  • 53
  • 8
  • 1
    You cannot return data from a Firebase listener – OneCricketeer Aug 29 '18 at 12:05
  • Note that the `if(d.getKey().equals("waiting list"));` is completely useless, since [it executes an empty statement if the condition is true](https://stackoverflow.com/questions/14112515/semicolon-at-end-of-if-statement). – MC Emperor Aug 29 '18 at 12:58

1 Answers1

1

You're correct, the list is still null because you're never waiting for Firebase results over the network, your code is only setting a listener, then immediately returning an empty list.

Rather than this blocking call from your method

someList = getWaitingList (String uid);
// use someData

You should be doing something like this asynchronous call

// Do NOT make a list variable outside of this
getWaitingList (String uid, new Listener() {
    @Override onData(List someData) {
        // use someData, for example, update a listview 
    } 
});
// do NOT reference the list outside of the listener block method 

That being said,

Define an interface

interface UserListListener {
    void onUsers(List<FirebaseUser> users);
} 

Add a parameter to the method and make it void because you'll return from the interface

void getWaitingList (String uid, final UserListListener listener) {
   ... 

And the rest of the Firebase code is maybe okay, but you're looping over things, so I think you'd want to add to a list rather than just assign one, but anyway, here's the rest of the method using the Callback

GenericTypeIndicator<ArrayList<FirebaseUser>> t = new GenericTypeIndicator<ArrayList<FirebaseUser>>() {};
// Move the list inside this listener 
List<FirebaseUser> waitingList = new ArrayList<>();
for (DataSnapshot d:dataSnapshot.getChildren()){
    if(d.getKey().equals("waiting list")) {
        waitingList = d.getValue(t);
    }
}
listener.onUsers(waitingList); // end of the method

Then the external method call is responsible for implementation of the listener class, and getting the data.

You'll also want to implement onCancelled ; it's good practice to implement this first because it's where you will be notified of Firebase errors - do not leave it blank

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • Thank you very much, it really solved it but the problem is that I have a class "MyFirebase" that has a lot of functions like: getBook_id, getLocation, getWaiting_list etc, each function needs to "go" to firebase database and return the String/int/ArrayList. Do you have an idea of something more convenient/structural to implement it? – Yael Pesso Aug 29 '18 at 13:27
  • I might suggest using a more standardized framework that implements the above pattern like RxJava + RxFirebase, though the learning curve is a bit steep, but it essentially does the same that I showed manually. `Observable` is an interface that listens for functions to "return" and continue on with a `Subscribe` action – OneCricketeer Aug 29 '18 at 16:22