I am facing an issue here in my code. I am trying to get a collection in Firestore but sometimes the query returns a result and sometimes it doesn't.
Solutions I have applied
Turned off the persistence
Querying data through .get(Source. SERVER)
for (int i = 1; i <= 31; i ) { String date = String.format("d", i) "-" String.format("d", currentMonth) "-" 2022; int finalI = i; monthRef.document(date) .collection("AttendanceSections") .document(student.getCurrentSection()) .collection("AttendanceStudents") .whereEqualTo("StudentID", student.getStudentId()) .get(Source.SERVER) .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() { @Override public void onComplete(@NonNull Task<QuerySnapshot> task) { if (task.isSuccessful()) { if (task.getResult().size() > 0) { for (QueryDocumentSnapshot document : task.getResult()) { StudentAttendance studentAttendance = document.toObject(StudentAttendance.class); studentAttendance.setDate(date); attendanceList.add(studentAttendance); } } } else { Log.d(TAG, "onComplete: " task.getException().getMessage()); } if (finalI == 31) { Log.d(TAG, "onComplete: " attendanceList.size()); progressBar.setVisibility(View.INVISIBLE); if (attendanceList.size() > 0) { drawDecorators(); } } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { } });
}
Point to note here is the date that I passing in the loop.
String date = String.format("d", i) "-" String.format("d", currentMonth) "-" 2022;
On 20-09-2022 a collection exists but sometimes it returns results in the task and sometimes it doesn't. I am unable to figure out the solution.
Any help would be appreciated.
CodePudding user response:
With your current code, the order that the queries complete in is not guaranteed. If your query for day 31 doesn't have any results (like it would for certain months of the year), it is likely to finish before any of the other days causing your list to be rendered out before it's properly filled.
You need to correct this by correctly waiting for them all to complete first and then hiding the progress bar.
By using some java.util.Stream
APIs, you gain the flexibility to arbitrarily apply filters to your collection query, and then fetch and collate all matches into a single list of StudentAttendance
instances, while maintaining the correct order.
// create a list to hold all the fetch tasks
List<Task<Stream<StudentAttendance>>> fetchStudentsTasks = new ArrayList<Task<Stream<StudentAttendance>>>(31);
for (int i = 0; i <= 31; i ) {
// for each computed date, fetch the students who attended on those dates
String date = String.format("d", i) "-" String.format("d", currentMonth) "-" 2022;
fetchStudentsTasks.add(
monthRef.document(date)
.collection("AttendanceSections")
.document(student.getCurrentSection())
.collection("AttendanceStudents")
.whereEqualTo("StudentID", student.getStudentId()) // omitting this line would get all students in attendance
.get(Source.SERVER)
.continueWith(t -> { // continueWith manipulates completed tasks, returning a new task with the given result
// The t.getResult() below will throw an error if the get
// documents task failed, effectively rethrowing it, which
// is OK here. If you want to ignore any failed queries,
// return Stream.empty() when t.isSuccessful() is false.
return StreamSupport
.stream(t.getResult().spliterator(), false) // streams the documents in the snapshot so we can iterate them
.map(document -> { // take each document and convert it to a StudentAttendance instance, with the right date
StudentAttendance studentAttendance = document.toObject(StudentAttendance.class);
studentAttendance.setDate(date);
return studentAttendance;
}) // this returned Stream is 'open', waiting for further processing
})
);
}
Tasks.whenAll(fetchStudentsTasks)
.addOnSuccessListener(() -> {
// if here, all queries returned successfully, update the list
attendanceList = fetchStudentsTasks
.stream()
.flatMap(t -> t.getResult()) // pull out the streams of StudentAttendance instances and merge them into one stream (closing each child stream when finished)
.collect(Collectors.toList()) // join all the StudentAttendance instances into one large ordered list
Log.d(TAG, "onComplete: " attendanceList.size());
progressBar.setVisibility(View.INVISIBLE);
if (attendanceList.size() > 0) {
drawDecorators();
}
})
.addOnFailureListener(() -> {
// if here, one or more queries failed
// todo: iterate over fetchStudentsTasks to pull out the exceptions
Log.d(TAG, "One or more fetch students tasks failed.");
});