2

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

Devil10
  • 1,853
  • 1
  • 18
  • 22
Alex Sicoe
  • 140
  • 2
  • 10
  • Did you call notifyDataSetChange after adding to adapter – Hemanth S Aug 22 '18 at 10:51
  • Well, in this case the project list is changed before setting the adapter, not after. So there shouldn't be a need to notify it. (Just updated the post with what's in onCreateView). Alternatively, I've tried to set an adapter with an empty list, then call my query method, then notify. Same result though. – Alex Sicoe Aug 22 '18 at 11:05

2 Answers2

1

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.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
0
projects.add(project);
adapter.notifyDataSetChange()

call notifyDataSetChange() after list add

Rofie Sagara
  • 289
  • 5
  • 17