Android + Firebase:同步进入异步函数

时间:2017-06-09 14:00:55

标签: java android firebase firebase-realtime-database

我正在创建一个函数(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);

我怎样才能做到这一点?

1 个答案:

答案 0 :(得分: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