Вопрос или проблема
Когда я создаю новый документ в репозитории с помощью database.collection("Groups").document(id).set(group)
и пытаюсь вернуть ссылку на документ, выполняя database.collection("Groups").document(id)
, ссылаясь на только что созданный документ, я не могу получить документ, так как Firebase Firestore работает асинхронно, и .set все еще добавляет новый документ, в результате чего я непреднамеренно возвращаю ссылку на документ до его создания.
Что я пробовал
- Возврат LiveData из репозитория, но это не задача репозитория
- Добавление LiveData в ViewModel, но ViewModel не должна изменять базу данных (добавляя новый документ в Firestore)
- Смотрел про Task.await, но это блокирует главный поток
Я ожидаю возврата DocumentReference из репозитория в ViewModel, чтобы я мог опубликовать его значение в моем MutableLiveData в ViewModel
Ответ или решение
Для того чтобы вернуть ссылку на документ, который был только что создан в репозитории, обратно в ViewModel, можно использовать подход с вызовом обратного метода (callback) или использовать CompletableFuture для работы с асинхронностью. Это упростит взаимодействие между репозиторием и ViewModel, не блокируя основной поток. Приведу пример на Java с использованием Firebase Firestore.
Шаги:
-
Создайте интерфейс обратного вызова:
Этот интерфейс будет содержать метод, который будет вызываться после завершения операции по созданию документа.public interface DocumentCallback { void onDocumentCreated(DocumentReference documentReference); void onError(Exception e); }
-
Обновите репозиторий:
Измените метод создания документа так, чтобы он принимал интерфейс обратного вызова. После завершения операции сохранения вызывайте метод обратного вызова.public class GroupRepository { private FirebaseFirestore database; public GroupRepository() { database = FirebaseFirestore.getInstance(); } public void createGroup(String id, Group group, DocumentCallback callback) { database.collection("Groups").document(id).set(group) .addOnSuccessListener(aVoid -> { DocumentReference documentReference = database.collection("Groups").document(id); callback.onDocumentCreated(documentReference); }) .addOnFailureListener(e -> callback.onError(e)); } }
-
Вызовите метод из ViewModel:
После обновления репозитория, вы можете вызывать данный метод из ViewModel и обрабатывать ссылку на документ, используя реализацию интерфейса обратного вызова.public class GroupViewModel extends ViewModel { private GroupRepository groupRepository; private MutableLiveData<DocumentReference> documentReferenceLiveData = new MutableLiveData<>(); public GroupViewModel() { groupRepository = new GroupRepository(); } public LiveData<DocumentReference> getDocumentReference() { return documentReferenceLiveData; } public void addGroup(String id, Group group) { groupRepository.createGroup(id, group, new DocumentCallback() { @Override public void onDocumentCreated(DocumentReference documentReference) { documentReferenceLiveData.postValue(documentReference); } @Override public void onError(Exception e) { // Обработка ошибки по мере необходимости } }); } }
Заключение
Используя данную архитектуру с интерфейсом обратного вызова, вы избегаете блокировки главного потока и одновременно сохраняете чистоту кода, соответствуя принципам разделения ответственности между репозиторием и ViewModel. Это позволит вам эффективно передавать обратную связь о созданных документах и управлять состоянием пользовательского интерфейса.