Java 如何在return语句运行之前等待异步方法完成?

Java 如何在return语句运行之前等待异步方法完成?,java,android,firebase,google-cloud-firestore,Java,Android,Firebase,Google Cloud Firestore,我需要返回语句的Firestore查询结果。该方法返回一个空列表,因为return语句是在任务完成之前运行的 这是我的DatabaseManager类中有问题的代码: public List<Image> getImagesFromDatabase(Query query){ List<Image> dataList= new ArrayList<Image>(); query.get().addOnCompleteListener(new

我需要返回语句的Firestore查询结果。该方法返回一个空列表,因为return语句是在任务完成之前运行的

这是我的DatabaseManager类中有问题的代码:

public List<Image> getImagesFromDatabase(Query query){

    List<Image> dataList= new ArrayList<Image>();
    query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull Task<QuerySnapshot> task) {
            if (task.isSuccessful()) {
                for (QueryDocumentSnapshot document : task.getResult()) {
                    Image image=document.toObject(Image.class);
                    image.setDocumentId(document.getId());
                    dataList.add(image);
                }
            } else {
                Log.d("DatabaseManager", "Error getting documents: ", task.getException());
            }
        }
    });
    return dataList;
}
公共列表getImagesFromDatabase(查询){
List dataList=new ArrayList();
query.get().addOnCompletListener(新的OnCompletListener()){
@凌驾
未完成的公共void(@NonNull任务){
if(task.issusccessful()){
对于(QueryDocumentSnapshot文档:task.getResult()){
Image=document.toObject(Image.class);
image.setDocumentId(document.getId());
dataList.add(图像);
}
}否则{
Log.d(“DatabaseManager”,“获取文档时出错:”,task.getException());
}
}
});
返回数据列表;
}
这是使用前面方法返回的列表的代码:

  private int getMaxNumberId(){
    Query query=dbManager.getCollectionReference().orderBy("numberId", Query.Direction.DESCENDING).limit(1);
    List<Image> images=dbManager.getImagesFromDatabase(query);
    Image maxImage=images.get(0);
    return maxImage.getNumberId();
}
private int getMaxNumberId(){
Query Query=dbManager.getCollectionReference().orderBy(“numberId”,Query.Direction.DESCENDING)。限制(1);
List images=dbManager.getImagesFromDatabase(查询);
图像最大化=图像。获取(0);
返回maxImage.getnumberrid();
}

据我所知,Future不是一个好的解决方案,我读过Future,也读过关于创建回调接口的内容,但由于return语句,我不知道如何实现该解决方案。

这段代码面临的问题是它没有以同步方式运行。这基本上意味着它并不是按照读取的方式执行的。
getImagesFromDatabase()
正在做的是:

  • 创建一个新的ArrayList并将其设置为
    dataList
    变量
  • 将查询发送到firebase(通过
    get()
    )并暂时忘记它。
  • 继续使用代码,从而返回空的
    数据列表
    ArrayList
  • 这是一个异步实现,因为它不会在继续之前等待答案。因此,当执行
    onComplete()
    时,您需要一种方法让您的代码知道Firebase已经返回了您的结果,因为现在它所做的唯一事情是将您的结果设置为已返回的过时实例。 在这种情况下,我可以想到三种解决方案

    • 等待结果

      对于第一个解决方案,Firebase SDK应该提供一个有用的方法来等待您的查询,换句话说,冻结调用它的线程(很可能是UI线程,所以这不是一个好主意)。在搜索了一段时间后,但它似乎给出了不同的结果,这不是推荐的方法,所以让我们继续下一个方法

    注意:据报道,Firebase甚至不提供同步实现,因此也排除了此选项

    • 设置回调

    • 创建一个接口来表示所需的方法(即onSuccess、onFailure)
    • 通过匿名类将所述接口实例化为变量,并将该变量传递给
      getImagesFromDatabase()
      方法
    • 在Firebase的
      onComplete()
      方法中调用变量的方法(即
      variable.onSuccess(results)
    • 希望调用匿名类中的
      onSuccess()
      实现,在匿名类中,您可能可以使用结果所需的所有资源
    • 有关此项的更多详细信息,请查看

    • 使变量
      可观察

      任何
      可观察的
      变量都会在发生更改时通知您,只要您对其设置了
      观察者
      。您可以使用Android的
      .observe(lifecycleOwner,Observer{})
      方法来实现这一点,或者在您的项目中设置了它。这也符合Android关于基于事件的编程、MVVM体系结构的指导原则,一般来说,这将为您的思维省去很多麻烦

      您可以将ArrayList转换为,实例化它并按原样返回它。然后,您需要在此变量上设置一个侦听器/观察者,并最终在
      onComplete()
      中更新其值

    考虑到您可能需要重构某些方法(例如
    getMaxNumberId()
    ),以更具反应性的方式运行。特别是当您与Firebase通信时,要知道您必须以基于事件的方式工作,而不是以具有常见函数返回的顺序方式工作(当然,除非它们是可观察的!)


    希望这有帮助,Panos。

    作为Panos Gr,您可以使用
    界面
    。首先创建一个新接口,同样的类也可以

     private interface IQuery{
          void onSuccess(List<Image> imageList);
     }
    
    然后在方法
    getMaxNumberId

      private int getMaxNumberId(){
            Query query=dbManager.getCollectionReference().orderBy("numberId", Query.Direction.DESCENDING).limit(1);
            dbManager.getImagesFromDatabase(query, new IQuery() {
                @Override
                public void onSuccess(List<Image> imageList) {
                    Image maxImage=imageList.get(0);
                    return maxImage.getNumberId();
                }
            });
            Image maxImage=images.get(0);
            return maxImage.getNumberId();
      }
    
    private int getMaxNumberId(){
    Query Query=dbManager.getCollectionReference().orderBy(“numberId”,Query.Direction.DESCENDING)。限制(1);
    数据库中的dbManager.getImagesFromDatabase(查询,新IQuery(){
    @凌驾
    成功时公开作废(列表图像列表){
    图像最大值=imageList.get(0);
    返回maxImage.getnumberrid();
    }
    });
    图像最大化=图像。获取(0);
    返回maxImage.getnumberrid();
    }
    

    我希望你会明白这一点

    这对你有帮助吗:请检查副本,看看你如何解决这个问题。这里有两个答案。第二种方法是使用get()和相应的回调。@AlexMamo,谢谢,这很有效,但这是一个非常混乱的解决方案,至少对我来说是这样,因为我有很多其他代码依赖于get()的结果,因此,所有这些代码都必须在onResponse()中。另一种方法可能是使用Kotlin协程。
      private int getMaxNumberId(){
            Query query=dbManager.getCollectionReference().orderBy("numberId", Query.Direction.DESCENDING).limit(1);
            dbManager.getImagesFromDatabase(query, new IQuery() {
                @Override
                public void onSuccess(List<Image> imageList) {
                    Image maxImage=imageList.get(0);
                    return maxImage.getNumberId();
                }
            });
            Image maxImage=images.get(0);
            return maxImage.getNumberId();
      }