Wait until Firestore data is retrieved to launch an activity

Solution 1:

You cannot use something now that hasn't been loaded yet. Firestore loads data asynchronously, since it may take some time for this. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds before that data is available. If you want to pass a list of objects of type Attraction to another method, just call that method inside onSuccess() method and pass that list as an argument. So a quick fix would be this:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference attractionsRef = rootRef.collection("attractions");

attractionsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
    @Override
    public void onComplete(@NonNull Task<QuerySnapshot> task) {
        if (task.isSuccessful()) {
            List<Attraction> attractionsList = new ArrayList<>();
            for (QueryDocumentSnapshot document : task.getResult()) {
                Attraction attraction = document.toObject(Attraction.class);
                attractionsList.add(attraction);
            }
            methodToProcessTheList(attractionsList);
        }
    }
});

So remember, onSuccess() method has an asynchronous behaviour, which means that is called even before you are getting the data from your database. If you want to use the attractionsList outside that method, you need to create your own callback. To achieve this, first you need to create an interface like this:

public interface MyCallback {
    void onCallback(List<Attraction> attractionsList);
}

Then you need to create a method that is actually getting the data from the database. This method should look like this:

public void readData(MyCallback myCallback) {
    attractionsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull Task<QuerySnapshot> task) {
            if (task.isSuccessful()) {
                List<Attraction> attractionsList = new ArrayList<>();
                for (QueryDocumentSnapshot document : task.getResult()) {
                    Attraction attraction = snapshot.toObject(Attraction.class);
                    attractionsList.add(attraction);
                }
                myCallback.onCallback(attractionsList);
            }
        }
    });
}

In the end just simply call readData() method and pass an instance of the MyCallback interface as an argument wherever you need it like this:

readData(new MyCallback() {
    @Override
    public void onCallback(List<Attraction> attractionsList) {
        //Do what you need to do with your list
    }
});

This is the only way in which you can use that attractionsList object outside onSuccess() method. For more informations, you can take also a look at this video.