Структура моей базы данных Firestore выглядит так:
... Коллекция с обычными объектами.
... Коллекция с объектами тренировки. С атрибутами
-> RoutineKey: хранит ключ процедуры, из которой создана тренировка.
-> ExerciseEntryKeys: ArrayList<String> ключей ExerciseEntry из тренировки
... Коллекция с объектами ExerciseEntries.
Теперь я хочу загрузить каждую тренировку из программы и записи упражнений тренировки. Для этого после загрузки рутинного объекта я делаю следующее.
for (final DocumentSnapshot doc : documentSnapshots.getDocuments()) {
final WorkoutSNR workout = doc.toObject(WorkoutSNR.class);
workout.setKey(doc.getId());
workoutsFromRoutine.add(workout);
fm.getColRefExerciseEntries().whereEqualTo("workoutKey", workout.getKey()).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
if (documentSnapshots.isEmpty()) {
prg.setVisibility(View.GONE);
processData();
} else {
for (int i = 0; i < workout.getExcersiseEntryKeys().size(); i++) {
fm.getDocRefExerciseEntrie(workout.getExcersiseEntryKeys().get(i)).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
@Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
final ExcersiseEntrySNR entry = documentSnapshot.toObject(ExcersiseEntrySNR.class);
entry.setKey(documentSnapshot.getId());
workout.getExcersises().add(entry);
processData();
prg.setVisibility(View.GONE);
Collections.sort(workout.getExcersises(), new Comparator<ExcersiseEntrySNR>() {
@Override
public int compare(ExcersiseEntrySNR e1, ExcersiseEntrySNR e2) {
if (e1.getPosition() < e2.getPosition()) {
return -1;
} else if (e1.getPosition() > e2.getPosition()) {
return 1;
} else {
return 0;
}
}
});
}
});
}
}
}
});
}
}
});
Это работает так, как должно, но, как вы можете видеть, я звоню:
processData();
prg.setVisibility(View.GONE);
Collections.sort(workout.getExcersises(), new Comparator<ExcersiseEntrySNR>() {
@Override
public int compare(ExcersiseEntrySNR e1, ExcersiseEntrySNR e2) {
if (e1.getPosition() < e2.getPosition()) {
return -1;
} else if (e1.getPosition() > e2.getPosition()) {
return 1;
} else {
return 0;
}
}
});
Всегда, когда ExerciseEntry был успешно загружен. В этом нет необходимости, и я хочу вызывать этот код только один раз (Every ExerciseEnry для каждой тренировки в программе).
Как лучше всего заметить, что все загружено? Предоставляет ли Firestore какую-либо функцию для этого?
Я пробовал иметь целое число, которое подсчитывает количество успешных загрузок ExerciseLoads и Workout, но я могу получить доступ только к конечным переменным внутри вложенного класса (так оно и называется?).
Да, точно. Извините, если это было непонятно




How do I know when the data is completely loaded from the database?
Вы можете добавить флаг к каждому объекту Routine и Workout со значением false и, как только вы загрузите эти объекты, установить значение true, но это не то, как все работает с Firestore. Вы не можете узнать, когда объект из базы данных будет загружен, потому что Cloud Firestore is also a realtime database и получение данных может никогда не завершиться. Вот почему он назван realtime database, потому что в любой момент данные в этих объектах Routine и Workout могут быть изменены, свойства могут быть добавлены или удалены.
Вы можете использовать CompletionListener только тогда, когда вы используете данные написать или Обновить, и вы будете уведомлены, когда операция будет подтверждена серверами базы данных, но вы не можете использовать этот интерфейс при чтении данных.
Так я ничего не могу там сделать? Я имею в виду, что сортировка моего ArrayList каждый раз, когда объект загружается, не подходит.
Сортировка ArrayList каждый раз при загрузке объекта не означает, что вы завершили загрузку данных из базы данных. Поскольку в любой момент ваша база данных может быть изменена, вы никогда не сможете сказать, что ваша загрузка завершена. Но это не недостаток, так работает база данных в реальном времени.
Но я не использую ChangeListener или что-то еще. Я просто загружаю документы, и даже если в базе данных есть какие-либо изменения, я не получаю дополнительных документов. Поэтому я не понимаю, почему я не могу заметить, что загрузил все существующие документы в то время, когда я начинаю загружаться.
Когда вы используете вызов get (), это означает, что вы получаете данные из базы данных, и нет никакого смысла говорить, что вы закончили загрузку. Обратите внимание, что ни КоллекцияСсылка, ни DocumentReference не имеют метода, который позволил бы вам достичь этого. И как я уже упоминал в своем ответе, вы можете добиться этого только при использовании операции записи.
Хорошо, поэтому Firestore не предоставляет мне никакой функции для этого, но я должен иметь возможность иметь 'int count' для тренировок и упражнений и проверять в onSuccess, равно ли количество тренировок размеру QuerySnapshot и если количество упражнений равно размеру ExerciseEntryKeys, верно? Проблема в том, что я не могу увеличить переменную счетчика внутри onSuccess, потому что я могу получить доступ только к конечным переменным ...
Нет. Если вы хотите подсчитать количество документов в коллекции, это - это то, как вы можете это сделать, но, к сожалению, я боюсь, что это не решит проблему, связанную с завершением загрузки данных. Что касается конечных переменных, просто объявите, что эта переменная имеет локальную область видимости.
вы сказали в этой теме, что нет метода getDocumentCount (), но это не «documentSnapshots.getDocuments (). size ()» (из QuerySnapshot)? Если да, то я не понимаю, почему подсчет моих успешных нагрузок не работает. Мне кажется, что с базой данных в реальном времени это намного проще, возможно, мне стоит снова вернуться к этой базе данных, хотя мне действительно нравится концепция коллекции / документа. Спасибо за вашу помощь, кстати.
Да, вы можете подсчитать количество документов с помощью task.getResult().size(), но это не значит, что вы узнаете, когда загрузка данных завершится. Я не сказал, что пересчитать документы не получится, я просто сказал, что это поможет вам в том, что вы хотите. Представьте, что в коллекции есть 100 документов. Вы используете метод подсчета этих документов, но тем временем добавляется один новый документ. Результатом вашего метода будет 100, но реальный номер документа - 101. Таким образом, вы получите несогласованные данные. Таким образом, вы не можете узнать, когда загрузка данных завершилась.
Пожалуйста. Надеюсь, я был достаточно ясен, чтобы вы поняли эту концепцию. Вы также можете дождаться других ответов, но если вы считаете, что мой ответ вам помог, подумайте о том, чтобы принять его и проголосовать. Спасибо!
Все в порядке? Могу я помочь вам с другой информацией?
Спасибо, я предложил свое текущее окончательное решение. Я мог бы вернуться к базе данных реального времени, потому что там это работает намного лучше.
Итак, если кому-то интересно, каково мое Решение в конце, вот мой текущий Код:
fm.getColRefWorkoutSNR().whereEqualTo("routineKey", routineKey).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
final int workoutSize = documentSnapshots.getDocuments().size();
for (final DocumentSnapshot doc : documentSnapshots.getDocuments()) {
final WorkoutSNR workout = doc.toObject(WorkoutSNR.class);
workout.setKey(doc.getId());
workoutsFromRoutine.add(workout);
fm.getColRefExerciseEntries().whereEqualTo("workoutKey", workout.getKey()).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
if (documentSnapshots.isEmpty()) {
prg.setVisibility(View.GONE);
processData();
} else {
if (workout.getExcersiseEntryKeys().size() > 0) {
for (int i = 0; i < workout.getExcersiseEntryKeys().size(); i++) {
fm.getDocRefExerciseEntrie(workout.getExcersiseEntryKeys().get(i)).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
@Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
final ExcersiseEntrySNR entry = documentSnapshot.toObject(ExcersiseEntrySNR.class);
entry.setKey(documentSnapshot.getId());
workout.getExcersises().add(entry);
if (workout.getExcersises().size() == workout.getExcersiseEntryKeys().size()) {
increaseFullyLoadedWorkouts();
}
if (fullyLoadedWorkouts == workoutSize) {
processData();
prg.setVisibility(View.GONE);
}
}
});
}
} else {
increaseFullyLoadedWorkouts();
if (fullyLoadedWorkouts == workoutSize) {
processData();
prg.setVisibility(View.GONE);
}
}
}
}
});
}
}
});
Как видите, я проверяю, все ли упражнения загружены для тренировки, и если это так, я увеличиваю счетчик «fullLoadedWorkout». Затем я проверяю, соответствует ли счетчик размеру тренировки, и если это так, я знаю, что я «полностью» загрузил свои данные.
Я знаю, что это не лучший способ сделать это, но это единственное решение, которое я могу представить на данный момент. Кажется, это намного проще в базе данных реального времени, и я все еще подумываю о том, чтобы вернуться к ней. Любые предложения по улучшению приветствуются.
Итак, в чем основной вопрос, вы хотите знать, когда данные полностью загружены из базы данных?