【问题标题】:Java/Firestore - Wait for data to be read before looping to next item (Async)Java/Firestore - 在循环到下一项之前等待读取数据(异步)
【发布时间】:2020-08-20 17:53:45
【问题描述】:

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

我的 Firestore 数据库中有 2 个实体:优惠和用户。

每个优惠都由用户发布。

检索所有优惠后,我想将有关用户的信息(名称、profileImage、描述)添加到 OffersViewModel(以将其绑定到我拥有的 RecicleView)。

问题是在报价被传递到外层之前我无法同步用户个人资料信息的读取(所以我可以将它们绑定到 1 个模型中)

这是我所拥有的:

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);
    }

   



}

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

我用Logs尝试了一些调试,围绕回调,执行顺序是这样的:

1-Before 循环 -> 列表不变

2-In 循环 -> 列表不变

3-After 循环 -> 列表不变

4-In callBack -> 列表已更改

感谢您对此事的任何帮助!

【问题讨论】:

  • 如果你要使用 MVVM,减少耦合。请检查 LiveData。 LiveData 比回调更好。
  • 您可以尝试为此使用协程。本质上,您可以使用挂起函数来获取第一个数据,然后等待第二个挂起函数返回其余数据。如果将其与 livedata 结合使用,则不必再使用回调并监听更改。查看文档 [此处][1] [1]:kotlinlang.org/docs/reference/coroutines-overview.html
  • @Abhimanyu 我在外层使用LiveData
  • @MateoHervas Java 也支持这个吗?

标签: java android asynchronous google-cloud-firestore callback


【解决方案1】:

所以我的做法毕竟是这样的:

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 每次写入新信息时都会更新适配器。

即使它有效,我认为有点粗略。我将不胜感激任何其他方式来获得这个(预期的)结果

【讨论】:

    猜你喜欢
    • 2021-07-12
    • 2021-09-10
    • 1970-01-01
    • 2021-09-14
    • 2021-03-06
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    • 2019-07-13
    相关资源
    最近更新 更多