Alex Sicoe
Alex Sicoe

Reputation: 150

Querying a list of objects from Firebase Firestore on Android

I'm trying to make a method that queries a list of projects from my Cloud Firestore database. I would then set a RecyclerView adapter with said list and it should display nicely. As of now, the RecyclerView is empty. (I've also tested the RecyclerView with dummy projects and they display just fine)

The projects list remains empty in the end of my method. Logs show up in a weird order (last log displays before the other logs). The logs order make me suspect that there's some separate thread/s running in the listener. I'm not exactly sure how to synchronize them.

private List<Project> projects;
private FirebaseFirestore db;

... In onCreateView() (i'm working in a fragment):

 db = FirebaseFirestore.getInstance();
 queryAllProjects();
 recyclerView.setAdapter(new ProjectRecyclerViewAdapter(projects, ...

...

 private void queryAllProjects() {
        projects = new ArrayList<>(); 
        //I've already tried to make a local list and return that, however, 
        //the compiler would force me to declare the list as final here, and it wouldn't solve anything.
        db.collection("projects")
                .get()
                .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                    @Override
                    public void onComplete(@NonNull Task<QuerySnapshot> task) {
                        if (task.isSuccessful()) {
                            for (QueryDocumentSnapshot document : task.getResult()) {
                                Log.d(TAG, document.getId() + " => " + document.getData());
                                Project project = document.toObject(Project.class);
                                projects.add(project);
                            }
                            Log.d(TAG, "After for loop: " + projects.toString()); 
                            //Here the list is OK. Filled with projects. 
                            //I'd like to save the state of the list from here
                        } else {
                            Log.d(TAG, "Error getting document: ", task.getException());
                            Toast.makeText(getContext(), R.string.error, Toast.LENGTH_SHORT).show();
                        }
                    }
                });
        Log.d(TAG, "End of method: " + projects.toString()); 
        //Oddly enough, this log displays before the other logs. 
        //Also, the list is empty here, which is probably what I'm unintentionally feeding into the Recycler View's adapter
    }

Here's the official documentation I've been following

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

Upvotes: 2

Views: 1318

Answers (2)

Alex Mamo
Alex Mamo

Reputation: 138824

You cannot use now something that hasn't been loaded yet. With other words, you cannot simply make your projects ArrayList as a global variable and use its value outside the onComplete() method because it will always be null due the asynchronous behaviour of this method. This means that by the time you are trying to use the following log statement:

Log.d(TAG, "End of method: " + projects.toString()); 

The data hasn't finished loading yet from the database and that's why is not accessible.

A quick solve for this problem would be to move this line of code inside the onComplete() method, otherwise I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.

There is also antoher answer that shows how to get your list outside the callback.

Upvotes: 1

Rofie Sagara
Rofie Sagara

Reputation: 323

projects.add(project);
adapter.notifyDataSetChange()

call notifyDataSetChange() after list add

Upvotes: 0

Related Questions