【问题标题】:firestore read is asynchronous and I want synchronous behaviourfirestore 读取是异步的,我想要同步行为
【发布时间】:2018-12-29 14:03:23
【问题描述】:

我想将我从云端读取的数据存储在本地。 为此,我使用了一个全局变量 (quizzes) 来保存所有数据。

为此,当我构建 Quiz 对象时,我需要确保在创建它们之前,相关数据已经从云端下载。因为从 firestore 读取数据时,它是异步发生的。

我之前没有强制执行此操作(等待读取完成) - 我只是使用了 onSuccess 侦听器,但我遇到了同步问题,因为在我使用来自的数据创建 Quiz 对象之前读取任务尚未完成云。

我用一种非常原始的“忙等待”方式解决了这个问题,直到从云端读取完成。我知道这是非常愚蠢的做法,是一种非常糟糕的做法,并且会使应用程序变得超级慢,我相信有更好的方法来解决这个问题。

 private void downloadQuizzesFromCloud(){


    String user_id = FirebaseAuth.getInstance().getCurrentUser().getUid();
    final FirebaseFirestore db = FirebaseFirestore.getInstance();
    CollectionReference quizzesRefrence = db.collection("users").document(user_id).collection("quizzes");

    Task<QuerySnapshot> task = quizzesRefrence.get();
    while(task.isComplete() == false){
        System.out.println("busy wait");
    }


    for (QueryDocumentSnapshot document : task.getResult()) {
        Quiz quizDownloaded = getQuizFromCloud(document.getId());
        quizzes.add(quizDownloaded);
    }

}

我在网上查看了 firestore 和 firebase 的文档,但没有找到任何可以使用的东西。 (例如尝试使用“等待”方法)但没有帮助。

我还能做些什么来解决这个同步问题?

【问题讨论】:

  • 你可以使用 MutableLiveData,观察 onChange 并用你的数据做你想做的事
  • 作为一般说明,没有人应该尝试将异步操作转换为移动应用程序中的同步操作。这会导致问题。请阅读为什么所有 Firebase API 都是异步的:medium.com/google-developers/…

标签: android firebase android-asynctask google-cloud-firestore


【解决方案1】:

我不明白你是否尝试过这个解决方案,但我认为这样更好更容易:将onCompleteListener 添加到从get() 方法返回的Task 对象中,如果任务成功, 你可以做你所有的事情,像这样:

private void downloadQuizzesFromCloud(){


String user_id = FirebaseAuth.getInstance().getCurrentUser().getUid();
final FirebaseFirestore db = FirebaseFirestore.getInstance();
CollectionReference quizzesRefrence = db.collection("users").document(user_id).collection("quizzes");

quizzesRefrence.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull Task<QuerySnapshot> task) {
            if (task.isSuccesful()) {
               for (QueryDocumentSnapshot document : task.getResult()) {
                    Quiz quizDownloaded = getQuizFromCloud(document.getId());
                    quizzes.add(quizDownloaded);
               }
             }
         });
}
}

通过这种方式,您将在下载数据后立即执行所有您需要做的事情(这里是 for 循环)

【讨论】:

  • 这是我开始使用的解决方案,但是,它不起作用。在您建议的实现中,如果我想使用变量 quizzes(例如在读取之后,或在不同的函数中),那么任务可能不会完成并且 quizzes 中的数据将不正确
  • 为什么说任务还没有完成呢?如果我们在 onComplete 方法中,则任务已经完成
  • 在 OnComplete 的范围内,是的,当然,任务完成了,但是,如果我要在代码中的其他地方使用变量“quizzes”(例如在函数之前“downloadQuizzesFromCloud”已完成)任务未完成,我可能在“quizzes”变量中有不正确的数据。我知道这一点,因为我尝试并调试了您的建议(这就是首先导致同步问题的原因)
  • 试图将异步 API 调用转换为同步序列是令人头疼的问题。如果您有更多代码需要访问已加载的测验,则该代码应 onComplete 内或从那里调用。没有其他方法可以解决它。另请参阅我的答案以获得更长的解释/示例:stackoverflow.com/questions/50434836/…
  • 好的,现在我明白了;我只能建议您使用布尔变量(例如“已下载”)并仅在该布尔为真时才使用“测验”对象,但我认为您已经尝试过。我帮不了你,一个在线请求不能同步;你唯一能做的就是像你的问题一样停止这个过程,但是在一个单独的线程中做它以避免 ANR
【解决方案2】:

您可以进行自己的回调。为此,制作一个接口

public interface FireStoreResults {
    public void onResultGet();
}

现在当你得到结果时发回这个电话

public void readData(final FireStoreResults){
    db.collection("users").document(user_id).collection("quizzes")
    .get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
            @Override
            public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
                for (QueryDocumentSnapshot document : task.getResult()) {
                     Quiz quizDownloaded = getQuizFromCloud(document.getId());
                     quizzes.add(quizDownloaded);
                 }
                results.onResultGet();
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                results.onResultGet();
            }
        });   
}

现在在您的活动或片段中

new YourResultGetClass().readData(new FireStoreResults(){
             @Override
             public void onResultGet() {
                    new YourResultGetClass().getQuizzes(); //this is your list of quizzes
                    //do whatever you want with it
            }

希望这是有道理的!

【讨论】:

    猜你喜欢
    • 2014-10-11
    • 2011-12-27
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-12
    • 1970-01-01
    相关资源
    最近更新 更多