java - Java/Firestore - Wait for data to be read before looping to next item (Async)
问题描述
I am trying to implement a VMMV architecture on my project in order to have low coupling between objects.
I have 2 entities in my Firestore database: Offers and Users.
Each offer is posted by a user.
After retrieving all offers, I want to add information about the user (name, profileImage, description) to the OffersViewModel (to bind it to the RecicleView I have).
The problem is I cannot sync the reading of user profile information before the offers are being passed to the outer layers(so I can bind them in 1 model)
Here is what I have:
package com.kaju.activities.workingActivity.Repository;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QuerySnapshot;
import com.kaju.activities.workingActivity.Model.ProviderOfferModel;
import com.kaju.activities.workingActivity.Model.ProviderProfileModel;
import java.util.List;
public class FirestoreOfferRepository {
//We get the currently linked firebase firestore database
private FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();
private CollectionReference offersReference = firebaseFirestore.collection("offers");
private OnFirestoreTaskComplete onFirestoreTaskComplete;
public FirestoreOfferRepository(OnFirestoreTaskComplete onFirestoreTaskComplete){
this.onFirestoreTaskComplete = onFirestoreTaskComplete;
}
public void getOffersData(final String annoucementID){
Query offersForAnnoucement = offersReference.whereEqualTo("announcementID", annoucementID);
offersForAnnoucement.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if(task.isSuccessful()){
final List<ProviderOfferModel> newOffers = task.getResult().toObjects(ProviderOfferModel.class);
//We try to get the information for each user
for(final ProviderOfferModel currentOffer : newOffers){
String userID = currentOffer.getUserID();
getUserProfileData(new UserDataCallback() {
@Override
public void userReadDataCallback(ProviderProfileModel currentUser) {
int index = newOffers.indexOf(currentOffer);
newOffers.get(index).setProvider(currentUser);
//This part here is executed only after the loop is over
}
}, userID);
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// I want to wait here so the above callBacks are finished
//And we send the data to the outside layers
onFirestoreTaskComplete.offerDataAdded(newOffers);
}else{
onFirestoreTaskComplete.onError(task.getException());
}
}
});
}
public void getUserProfileData(final UserDataCallback userDataCallback, String userID)
{
firebaseFirestore.collection("users").document(userID).get()
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
if(task.isSuccessful()) {
ProviderProfileModel currentUser = task.getResult().toObject(ProviderProfileModel.class);
userDataCallback.userReadDataCallback(currentUser);
}
}
});
}
public interface OnFirestoreTaskComplete{
void offerDataAdded(List<ProviderOfferModel> offerRepositoryData);
void onError(Exception e);
}
public interface UserDataCallback{
void userReadDataCallback(ProviderProfileModel currentUser);
}
}
I found a tutorial on YT which explains how I should retrieve the data from the callback but it doesn't seem to work(or I implemented it badly).
I have tried some debugging with Logs, surrounding the callback, and the order of executing is like this:
1-Before loop -> List unchanged
2-In loop -> List unchanged
3-After loop -> List unchanged
4-In callBack -> List changed
I appreciate any help on the matter !
解决方案
所以我这样做的方式毕竟是这样的:
public void getOffersData(final String annoucementID){
Query offersForAnnoucement = offersReference.whereEqualTo("announcementID", annoucementID);
offersForAnnoucement.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if(task.isSuccessful()){
final List<ProviderOfferModel> newOffers = task.getResult().toObjects(ProviderOfferModel.class);
//We try to get the information for each user
for(final ProviderOfferModel currentOffer : newOffers){
String userID = currentOffer.getUserID();
getUserProfileData(new UserDataCallback() {
@Override
public void userReadDataCallback(ProviderProfileModel currentUser) {
int index = newOffers.indexOf(currentOffer);
newOffers.get(index).setProvider(currentUser);
onFirestoreTaskComplete.offerDataAdded(newOffers);
}
}, userID);
}
//And we send the data to the outside layers
}else{
onFirestoreTaskComplete.onError(task.getException());
}
}
});
}
基本上,每次我为另外 1 个用户检索数据时,我都会将带有用户信息的新更新列表发送到 ViewModel 和 LiveData(到外部层)。
它有效,我认为它确实有效,因为 LiveData 侦听器 onChanged 每次写入新信息时都会更新适配器。
即使它有效,我认为有点粗略。我将不胜感激获得此(预期)结果的任何其他方式
推荐阅读
- javascript - 从表中读取输入值时出现问题
- c++ - 在 FreeRTOS 中使用字符串队列
- node.js - 使用 nodejs 加载经过训练的 mnist 模型
- bash - 检测默认交互式 shell 不适用于 shell 脚本
- javascript - 使用实例化时 SVG 访问路径 (shadowDOM) (vanilla javascript)
- spring-boot - 无法从 ElasticSearch 获取数据
- javascript - JS 和空格的问题 - Ruby on Rails 和 JS
- typescript - Typescript 导入模块源而不是编译输出
- c - 找不到 __fpurge(stdin); 的替换
- maven - 如何通过 jmeter-maven-plugin 覆盖参数?