Java/Firestore – 在循环至下一项之前等待数据被读取(异步)

huangapple go评论119阅读模式
英文:

Java/Firestore - Wait for data to be read before looping to next item (Async)

问题

我正在尝试在我的项目中实现一个VMMV架构,以便在对象之间实现低耦合。

我的Firestore数据库中有两个实体:Offers(优惠)和Users(用户)。

每个优惠都是由一个用户发布的。

在检索到所有优惠后,我想将有关用户的信息(姓名、个人头像、描述)添加到OffersViewModel(以便将其绑定到我拥有的RecicleView)。

问题是,在将优惠传递给外部层之前,我无法同步读取用户配置文件信息(以便可以将它们绑定在一个模型中)。

以下是我拥有的内容:

  1. // 代码部分已略去

我在YT上找到了一个教程,解释了我应该如何从回调中检索数据,但似乎不起作用(或者我实现得不好)。

我已经尝试过一些调试方法,比如使用日志记录,对回调进行封装,执行顺序如下:

1- 循环之前 -> 列表未更改
2- 循环内 -> 列表未更改
3- 循环之后 -> 列表未更改
4- 在回调内 -> 列表已更改

对于这个问题,我非常感谢任何帮助!

英文:

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:

  1. package com.kaju.activities.workingActivity.Repository;
  2. import android.util.Log;
  3. import androidx.annotation.NonNull;
  4. import com.google.android.gms.tasks.OnCompleteListener;
  5. import com.google.android.gms.tasks.Task;
  6. import com.google.firebase.firestore.CollectionReference;
  7. import com.google.firebase.firestore.DocumentReference;
  8. import com.google.firebase.firestore.DocumentSnapshot;
  9. import com.google.firebase.firestore.FirebaseFirestore;
  10. import com.google.firebase.firestore.Query;
  11. import com.google.firebase.firestore.QuerySnapshot;
  12. import com.kaju.activities.workingActivity.Model.ProviderOfferModel;
  13. import com.kaju.activities.workingActivity.Model.ProviderProfileModel;
  14. import java.util.List;
  15. public class FirestoreOfferRepository {
  16. //We get the currently linked firebase firestore database
  17. private FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();
  18. private CollectionReference offersReference = firebaseFirestore.collection("offers");
  19. private OnFirestoreTaskComplete onFirestoreTaskComplete;
  20. public FirestoreOfferRepository(OnFirestoreTaskComplete onFirestoreTaskComplete){
  21. this.onFirestoreTaskComplete = onFirestoreTaskComplete;
  22. }
  23. public void getOffersData(final String annoucementID){
  24. Query offersForAnnoucement = offersReference.whereEqualTo("announcementID", annoucementID);
  25. offersForAnnoucement.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
  26. @Override
  27. public void onComplete(@NonNull Task<QuerySnapshot> task) {
  28. if(task.isSuccessful()){
  29. final List<ProviderOfferModel> newOffers = task.getResult().toObjects(ProviderOfferModel.class);
  30. //We try to get the information for each user
  31. for(final ProviderOfferModel currentOffer : newOffers){
  32. String userID = currentOffer.getUserID();
  33. getUserProfileData(new UserDataCallback() {
  34. @Override
  35. public void userReadDataCallback(ProviderProfileModel currentUser) {
  36. int index = newOffers.indexOf(currentOffer);
  37. newOffers.get(index).setProvider(currentUser);
  38. //This part here is executed only after the loop is over
  39. }
  40. }, userID);
  41. }
  42. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  43. // I want to wait here so the above callBacks are finished
  44. //And we send the data to the outside layers
  45. onFirestoreTaskComplete.offerDataAdded(newOffers);
  46. }else{
  47. onFirestoreTaskComplete.onError(task.getException());
  48. }
  49. }
  50. });
  51. }
  52. public void getUserProfileData(final UserDataCallback userDataCallback, String userID)
  53. {
  54. firebaseFirestore.collection("users").document(userID).get()
  55. .addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
  56. @Override
  57. public void onComplete(@NonNull Task<DocumentSnapshot> task) {
  58. if(task.isSuccessful()) {
  59. ProviderProfileModel currentUser = task.getResult().toObject(ProviderProfileModel.class);
  60. userDataCallback.userReadDataCallback(currentUser);
  61. }
  62. }
  63. });
  64. }
  65. public interface OnFirestoreTaskComplete{
  66. void offerDataAdded(List<ProviderOfferModel> offerRepositoryData);
  67. void onError(Exception e);
  68. }
  69. public interface UserDataCallback{
  70. void userReadDataCallback(ProviderProfileModel currentUser);
  71. }
  72. }

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 !

答案1

得分: 1

以下是翻译好的内容:

这样,我最终做的方式是这样的:

  1. public void getOffersData(final String annoucementID){
  2. Query offersForAnnoucement = offersReference.whereEqualTo("announcementID", annoucementID);
  3. offersForAnnoucement.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
  4. @Override
  5. public void onComplete(@NonNull Task<QuerySnapshot> task) {
  6. if(task.isSuccessful()){
  7. final List<ProviderOfferModel> newOffers = task.getResult().toObjects(ProviderOfferModel.class);
  8. // 我们尝试获取每个用户的信息
  9. for(final ProviderOfferModel currentOffer : newOffers){
  10. String userID = currentOffer.getUserID();
  11. getUserProfileData(new UserDataCallback() {
  12. @Override
  13. public void userReadDataCallback(ProviderProfileModel currentUser) {
  14. int index = newOffers.indexOf(currentOffer);
  15. newOffers.get(index).setProvider(currentUser);
  16. onFirestoreTaskComplete.offerDataAdded(newOffers);
  17. }
  18. }, userID);
  19. }
  20. // 然后我们将数据发送给外部层
  21. }else{
  22. onFirestoreTaskComplete.onError(task.getException());
  23. }
  24. }
  25. });
  26. }

基本上,每当我为1个以上的用户检索数据时,我都会将包含用户信息的新更新列表发送到ViewModel和LiveData(发送到外部层)。

它能工作,我认为这是因为LiveData的监听器onChanged会在新信息写入时更新适配器。

即使它能工作,我认为这还有点不够完善。我会欣赏其他获得这个(预期)结果的方法。

英文:

So the way I did it after all is like this:

  1. public void getOffersData(final String annoucementID){
  2. Query offersForAnnoucement = offersReference.whereEqualTo(&quot;announcementID&quot;, annoucementID);
  3. offersForAnnoucement.get().addOnCompleteListener(new OnCompleteListener&lt;QuerySnapshot&gt;() {
  4. @Override
  5. public void onComplete(@NonNull Task&lt;QuerySnapshot&gt; task) {
  6. if(task.isSuccessful()){
  7. final List&lt;ProviderOfferModel&gt; newOffers = task.getResult().toObjects(ProviderOfferModel.class);
  8. //We try to get the information for each user
  9. for(final ProviderOfferModel currentOffer : newOffers){
  10. String userID = currentOffer.getUserID();
  11. getUserProfileData(new UserDataCallback() {
  12. @Override
  13. public void userReadDataCallback(ProviderProfileModel currentUser) {
  14. int index = newOffers.indexOf(currentOffer);
  15. newOffers.get(index).setProvider(currentUser);
  16. onFirestoreTaskComplete.offerDataAdded(newOffers);
  17. }
  18. }, userID);
  19. }
  20. //And we send the data to the outside layers
  21. }else{
  22. onFirestoreTaskComplete.onError(task.getException());
  23. }
  24. }
  25. });
  26. }

Basically, every time I retrieve data for 1 more user, I send the newly updated list with the user information to the ViewModel and to LiveData (to the outside layer).

It works and I think it does because of the LiveData listener onChanged which updates the Adapter everytime new information is written.

Even if it works, I think is a bit sketchy. I would appreciate any other way to obtain this (expected) result

huangapple
  • 本文由 发表于 2020年8月21日 01:53:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/63510722.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定