【问题标题】:Android + Firebase: synchronous for into an asynchronous functionAndroid + Firebase:同步for变成异步函数
【发布时间】:2017-06-09 14:00:55
【问题描述】:

我正在制作一个函数 (Java - Android),它应该返回一个包含 Firebase 数据的对象列表。我的问题是,我需要在遍历 for 中的所有项目后将结果发送给侦听器,看看代码:

final DatabaseReference beaconMessageRef = dataSnapshot.getRef().getRoot().child("region_messages/" + regionKey);
beaconMessageRef.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {

        if(!dataSnapshot.exists())
            FirebaseHelper.this.messageByBeaconListener.onSuccess(null);

        for (DataSnapshot regionMessageDS : dataSnapshot.getChildren()) {

            RegionMessage regionMessage = regionMessageDS.getValue(RegionMessage.class);
            String msgKey = regionMessageDS.getKey();

            final DatabaseReference messageRef = regionMessageDS.getRef().getRoot().child("messages/"+msgKey);
            messageRef.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {

                    if(dataSnapshot.exists()){
                        Message msg = dataSnapshot.getValue(Message.class);
                        FirebaseHelper.this.addMessageByBeacon(msg);
                    }
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {
                    FirebaseHelper.this.messageByBeaconListener.onFail(databaseError);
                }
            });
        }

        List<Message> msgs = FirebaseHelper.this.beaconMessageList;
        FirebaseHelper.this.beaconMessageList = null;
        FirebaseHelper.this.messageByBeaconListener.onSuccess(msgs);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        FirebaseHelper.this.messageByBeaconListener.onFail(databaseError);
    }
});

我需要在循环遍历 for 中的所有项目之后执行此行:FirebaseHelper.this.messageByBeaconListener.onSuccess(msgs);

我怎样才能做到这一点?

【问题讨论】:

    标签: java android firebase firebase-realtime-database


    【解决方案1】:

    异步的东西在 Android 上无法可靠地同步。每当你有这样做的冲动时,深呼吸并重复第一句话。或者在这里阅读我的答案:Setting Singleton property value in Firebase Listener

    相反,您将不得不做每个人都会做的事情:将需要数据的代码移动到数据可用时触发的回调中。

    在您的情况下,这有点棘手,因为您要加载多个项目。幸运的是,尽管您知道需要加载多少项目。因此,如果您引入一个计数器来跟踪已加载的项目数,您将知道何时完成:

    final DatabaseReference beaconMessageRef = dataSnapshot.getRef().getRoot().child("region_messages/" + regionKey);
    beaconMessageRef.addListenerForSingleValueEvent(new ValueEventListener() {
      @Override
      public void onDataChange(DataSnapshot dataSnapshot) {
        if(!dataSnapshot.exists())
          FirebaseHelper.this.messageByBeaconListener.onSuccess(null);
    
        for (DataSnapshot regionMessageDS : dataSnapshot.getChildren()) {
    
          RegionMessage regionMessage = regionMessageDS.getValue(RegionMessage.class);
          String msgKey = regionMessageDS.getKey();
    
          final Integer[] counter = new Integer[1];
          final DatabaseReference messageRef = regionMessageDS.getRef().getRoot().child("messages/"+msgKey);
          messageRef.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot innerSnapshot) {
              if(innerSnapshot.exists()){
                Message msg = innerSnapshot.getValue(Message.class);
                FirebaseHelper.this.addMessageByBeacon(msg);
              }
              counter[0] = new Integer(counter[0].intValue()+1);
              if (counter[0].equalTo(dataSnapshot.numChildren()) {
                List<Message> msgs = FirebaseHelper.this.beaconMessageList;
                FirebaseHelper.this.beaconMessageList = null;
                FirebaseHelper.this.messageByBeaconListener.onSuccess(msgs);
              }
            }
    
            @Override
            public void onCancelled(DatabaseError databaseError) {
              FirebaseHelper.this.messageByBeaconListener.onFail(databaseError);
            }
          });
        }
      }
    
      @Override
      public void onCancelled(DatabaseError databaseError) {
        FirebaseHelper.this.messageByBeaconListener.onFail(databaseError);
      }
    });
    

    有关单元素数组的说明,请参阅此答案:https://stackoverflow.com/a/5977866/209103

    【讨论】:

    • 感谢您的回答,它解决了问题。在使用 NodeJS 时,我经常遇到这种情况,我用 Promise 解决了它。我正在研究 Future 以检查我是否可以做同样的事情。但我喜欢你的解决方案,非常轻巧。
    • 嗨@frank,现在我遇到了同样的问题,我试图在for循环中调用firebase函数。帮帮我,我看不懂上面的代码!。
    猜你喜欢
    • 1970-01-01
    • 2018-01-17
    • 2012-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-24
    • 2021-09-23
    相关资源
    最近更新 更多