3

When I call listPost(), it will return NULL. I guess it doesn't wait for the listener to fetch the post from the firebase. How can I wait to fetch the post from firebase before arrayPost get returned?

public Post[] listPost() {
    ArrayList<Post> list = new ArrayList<Post>();

    // Fetch post from firebase
    postRef.addValueEventListener(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot snapshot) {
            for(DataSnapshot child : snapshot.getChildren()) {
                String id = child.getKey();
                String title = child.child("title").getValue().toString();
                String content = child.child("content").getValue().toString();
                String date = child.child("date").getValue().toString();
                String status = child.child("status").getValue().toString();

                Post post = new Post();
                post.setId(id);
                post.setTitle(title);
                post.setContent(content);
                post.setDate(date);
                post.setStatus(status);
                list.add(post);
            }
        }

        @Override
        public void onCancelled(FirebaseError error) {
            System.out.println("The read failed: " + error.getMessage());
        }
    });

    // Convert ArrayList to Array 
    Post[] arrayPost = new Post[list.size()]; 
    list.toArray(arrayPost);
    return arrayPost;
}
Rudra Saraswat
  • 71
  • 1
  • 13
  • 1
    In general (this is not Firebase-specific) you can just wait for the operation to finish using some combination of Java's `Object.wait` and `Object.notify` methods. I can't quickly find a good example right now, so hope this is enough to get you started until somebody provides an answer. – Frank van Puffelen Dec 16 '14 at 12:02
  • Hi there! Please [read the Java/Android guide](https://www.firebase.com/docs/android/guide/), which covers basic 101 fundamentals like reading data and using the event callbacks. – Kato Dec 23 '14 at 18:29

1 Answers1

3

While you can certainly turn listPost() into a synchronous method using something like semaphores, this is not the way Firebase is intended to work. For example, every time you call addValueEventListener() it will add a new listener which will be called whenever your data changes, once for every time you called listPost().

If the purpose of the listPost() method is to update some state somewhere (e.g. your UI), you can instead update the state directly from your onDataChanged() method. This will ensure that you only add one value event listener and updates in your data will always be reflected in your current state without needing to refresh.

// Setup once when your app loads
postRef.addValueEventListener(new ValueEventListener() {

    @Override
    public void onDataChange(DataSnapshot snapshot) {
        ArrayList<Post> list = new ArrayList<Post>();
        for(DataSnapshot child : snapshot.getChildren()) {
            String id = child.getKey();
            String title = child.child("title").getValue().toString();
            String content = child.child("content").getValue().toString();
            String date = child.child("date").getValue().toString();
            String status = child.child("status").getValue().toString();

            Post post = new Post();
            post.setId(id);
            post.setTitle(title);
            post.setContent(content);
            post.setDate(date);
            post.setStatus(status);
            list.add(post);
        }
        // Do something with your list of posts here
        updateSomething(list);
    }

    @Override
    public void onCancelled(FirebaseError error) {
        System.out.println("The read failed: " + error.getMessage());
    }
});

Since you have a list of children here you can also use a ChildEventListener here instead and react to child added, child changed and child removed events to update your state or UI.

jonnydee
  • 1,311
  • 1
  • 7
  • 11