13
votes

I want to get data from my Firebase Firestore database. I have a collection called user and every user has collection of some objects of the same type (My Java custom object). I want to fill my ArrayList with these objects when my Activity is created.

private static ArrayList<Type> mArrayList = new ArrayList<>();;

In onCreate():

getListItems();
Log.d(TAG, "onCreate: LIST IN ONCREATE = " + mArrayList);
*// it logs empty list here

Method called to get items to list:

private void getListItems() {
    mFirebaseFirestore.collection("some collection").get()
            .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                @Override
                public void onSuccess(QuerySnapshot documentSnapshots) {
                    if (documentSnapshots.isEmpty()) {
                        Log.d(TAG, "onSuccess: LIST EMPTY");
                        return;
                    } else {
                        for (DocumentSnapshot documentSnapshot : documentSnapshots) {
                            if (documentSnapshot.exists()) {
                                Log.d(TAG, "onSuccess: DOCUMENT" + documentSnapshot.getId() + " ; " + documentSnapshot.getData());
                                DocumentReference documentReference1 = FirebaseFirestore.getInstance().document("some path");
                                documentReference1.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
                                    @Override
                                    public void onSuccess(DocumentSnapshot documentSnapshot) {
                                        Type type= documentSnapshot.toObject(Type.class);
                                        Log.d(TAG, "onSuccess: " + type.toString());
                                        mArrayList.add(type);
                                        Log.d(TAG, "onSuccess: " + mArrayList);
                                        /* these logs here display correct data but when
                                         I log it in onCreate() method it's empty*/
                                    }
                                });
                            }
                        }
                    }
                }
            }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Toast.makeText(getApplicationContext(), "Error getting data!!!", Toast.LENGTH_LONG).show();
        }
    });
}
6
As it takes time to fetch the response that's why it shows empty at first, so if there is still any other problem then please be more specific about your problem. - Anmol317
No that is not problem, because I told you my list is fiilled with items in that last onSuccess method, I see that in log, but in onCreate method it's empty - Slaven Petkovic
you are fetching the data in the onCreate only, and it takes time to fetch it, so your log in the onCreate runs before even fetching the data. - Anmol317
@Slaven Petkovic Check my update code still if you want... - Gowthaman M

6 Answers

17
votes

The get() operation returns a Task<> which means it is an asynchronous operation. Calling getListItems() only starts the operation, it does not wait for it to complete, that's why you have to add success and failure listeners.

Although there's not much you can do about the async nature of the operation, you can simplify your code as follows:

private void getListItems() {
    mFirebaseFirestore.collection("some collection").get()
            .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                @Override
                public void onSuccess(QuerySnapshot documentSnapshots) {
                    if (documentSnapshots.isEmpty()) {
                        Log.d(TAG, "onSuccess: LIST EMPTY");
                        return;
                    } else {
                        // Convert the whole Query Snapshot to a list
                        // of objects directly! No need to fetch each
                        // document.
                        List<Type> types = documentSnapshots.toObjects(Type.class);   

                        // Add all to your list
                        mArrayList.addAll(types);
                        Log.d(TAG, "onSuccess: " + mArrayList);
                    }
            })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    Toast.makeText(getApplicationContext(), "Error getting data!!!", Toast.LENGTH_LONG).show();
                }
            });
}
2
votes

Try this..Working fine.Below function will get Realtime Updates from firebse as well..

db = FirebaseFirestore.getInstance();


        db.collection("dynamic_menu").addSnapshotListener(new EventListener<QuerySnapshot>() {
            @Override
            public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {

                if (e !=null)
                {

                }

                for (DocumentChange documentChange : documentSnapshots.getDocumentChanges())
                {
                 String   isAttendance =  documentChange.getDocument().getData().get("Attendance").toString();
                 String  isCalender   =  documentChange.getDocument().getData().get("Calender").toString();
                 String isEnablelocation = documentChange.getDocument().getData().get("Enable Location").toString();

                   }
                }
        });

More reference :https://firebase.google.com/docs/firestore/query-data/listen

If You do not want realtime updates refer Below Document

https://firebase.google.com/docs/firestore/query-data/get-data

1
votes

Here is a simplified example:

Create a collection "DownloadInfo" in Firebase.

And add a few documents with these fields inside it:

file_name (string), id (string), size (number)

Create your class:

public class DownloadInfo {
    public String file_name;
    public String id;
    public Integer size;
}

Code to get list of objects:

FirebaseFirestore db = FirebaseFirestore.getInstance();

db.collection("DownloadInfo")
        .get()
        .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                if (task.isSuccessful()) {
                     if (task.getResult() != null) {
                            List<DownloadInfo> downloadInfoList = task.getResult().toObjects(DownloadInfo.class);
                            for (DownloadInfo downloadInfo : downloadInfoList) {
                                doSomething(downloadInfo.file_name, downloadInfo.id, downloadInfo.size);
                            }
                        }
                    }
                } else {
                    Log.w(TAG, "Error getting documents.", task.getException());
                }
            }
        });
1
votes
    db.collection("users").get().then((querySnapshot) => {
    querySnapshot.forEach((doc) => {
        console.log(`${doc.id} => ${doc.data()}`);
    });

source:- https://firebase.google.com/docs/firestore/quickstart

0
votes

This is the code to get the list. Since this is an async task, it takes time that's why the list size shows empty at first. But including the source for the cache data will enable the previous list(and also its size) to be in memory until next task is performed.

Source source = Source.CACHE;
        firebaseFirestore
                .collection("collectionname")
                .get(source)
                .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                    @Override
                    public void onSuccess(QuerySnapshot documentSnapshots) {
                        if (documentSnapshots.isEmpty()) {

                            return;
                        } else {
                            // Convert the whole Query Snapshot to a list
                            // of objects directly! No need to fetch each
                            // document.
                            List<ModelClass> types = documentSnapshots.toObjects(ModelClass.class);
                            // Add all to your list
                            mArrayList.addAll(types);
                        }

                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {

                    }
                });
0
votes

let’s assume we have a document that contains a property of type array. This array is named users and holds a few User objects. The User class is very simple, contains only two properties and looks like this:

class User {
    public String name;
    public int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

And this is the database structure:

enter image description here

So our goal is to get in code the users array as a List<User>. To achieve that, we need to attach a listener on the document and use a get() call:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference applicationsRef = rootRef.collection("applications");
DocumentReference applicationIdRef = applicationsRef.document(applicationId);
applicationIdRef.get().addOnCompleteListener(task -> {
    if (task.isSuccessful()) {
        DocumentSnapshot document = task.getResult();
        if (document.exists()) {
            List<Map<String, Object>> users = (List<Map<String, Object>>) document.get("users");
        }
    }
});

To actually get the values out of from users array, we are calling:

document.get("users")

And we cast the object to a List<Map<String, Object>>. So this object is actually a List of Maps. It’s true that we can iterate through the Map, get the data out and create the List<User> ourselves. But as DocumentSnapshot contains different flavors for the get() method, according to each data type, getString(), getLong(), getDate(), etc, it would have been very helpful if we also had a getList() method, but unfortunately we don’t. So something like this:

List<User> users = document.getList("users");

It’s not possible. So how can we still get a List?

The simplest solution is to create another class that holds only a property of type List<User>. It looks like this:

class UserDocument {
    public List<User> users;

    public UserDocument() {}
}

And to directly get the list, only the following lines of code are needed:

applicationIdRef.get().addOnCompleteListener(task -> {
    if (task.isSuccessful()) {
        DocumentSnapshot document = task.getResult();
        if (document.exists()) {
            List<User> users = document.toObject(UserDocument.class).users;
            //Use the the list
        }
    }
});

Get From : How to map an array of objects from Cloud Firestore to a List of objects?