Firebase (GeoFire) 两次保存数据

Firebase (GeoFire) saves data twice

我试图在 Firebase 中用 GeoFire 保存 GeoLocationsGeoLocation 的键必须是服务器时间戳。所以数据模型如下:

{
  "geofire" : {
    "1515755844766" : {
      ".priority" : "ez53wur36x",
      "g" : "ez53wur36x",
      "l" : [ 39.66227391798104, -6.372992321848869 ]
    },
    "1515755844962" : {
      ".priority" : "ez53wur36x",
      "g" : "ez53wur36x",
      "l" : [ 39.66227391798104, -6.372992321848869 ]
    },
    "1515755851938" : {
      ".priority" : "s6xhjeruen",
      "g" : "s6xhjeruen",
      "l" : [ 14.78428771229891, 21.346221640706066 ]
    },
    "1515755852148" : {
      ".priority" : "s6xhjeruen",
      "g" : "s6xhjeruen",
      "l" : [ 14.78428771229891, 21.346221640706066 ]
    }
  },
  "serverTime" : 1515755852148
}

我刚刚执行了两次以下代码来获取这些值(四个值),因此它为每个 .setLocation() 保存了两次密钥(时间戳),在毫秒和秒之间有很小的差异。

为什么会这样?

//Get reference to Firebase DB
dbRef = FirebaseDatabase.getInstance().getReference();

// Get reference to Geofire inside FIrebaseDB
dbRefGeofire = FirebaseDatabase.getInstance().getReference("geofire");
geoFire = new GeoFire(dbRefGeofire);

dbRef.child("serverTime").setValue(ServerValue.TIMESTAMP);    //Executes TIMESTAMP function in firebase server and stores that value
dbRef.child("serverTime").addValueEventListener(new ValueEventListener() {    //Gets TIMESTAMP value from the server
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        serverTime = String.valueOf(dataSnapshot.getValue());
                        geoFire.setLocation(serverTime, new GeoLocation(latLng.latitude,latLng.longitude), new GeoFire.CompletionListener() {
                            @Override       //Save geolocation with timestamp in seconds
                            public void onComplete(String key, DatabaseError error) {
                                if (error != null) {
                                    Log.v("Informe","There was an error saving the location to GeoFire: " + error);
                                } else {
                                    Log.v("Informe","Location saved on server successfully!");
                                }
                            }
                        });
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {

                    }
                });

ValueEventListener执行了两次,如果你将断点设置在serverTime = String.valueOf(dataSnapshot.getValue()); 你会看清楚的,

为什么会这样?

因为你的 dbRef.child("serverTime").setValue(ServerValue.TIMESTAMP); 是异步的, 应用程序继续运行并设置一个新的valueEventListener,

dataSnapshot 中没有任何数据时会立即调用

然后,当你异步时 'setValue' 函数将完成并且 'onDataChange' 将再次调用(因为值已更改)

你可以直接加'datasnapshout.isExist()'来解决,

或像这样将 'onCompleteListener' 添加到您的 setValue 行:

    dbRef.setValue(ServerValue.TIMESTAMP, new DatabaseReference.CompletionListener() {
    @Override
    public void onComplete(DatabaseError databaseError, DatabaseReference dataRef) {
dbRef.child("serverTime").addValueEventListener(new ValueEventListener() {    //Gets TIMESTAMP value from the server
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        serverTime = String.valueOf(dataSnapshot.getValue());
                   geoFire.setLocation(serverTime, new GeoLocation(latLng.latitude,latLng.longitude), new GeoFire.CompletionListener() {
                    @Override       //Save geolocation with timestamp in seconds
                    public void onComplete(String key, DatabaseError error) {
                        if (error != null) {
                            Log.v("Informe","There was an error saving the location to GeoFire: " + error);


                 } else {
                                Log.v("Informe","Location saved on server successfully!");
                            }
                        }
                    });
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {

                }
            });
}

});

要解决此问题,请使用以下代码:

ValueEventListener eventListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        String serverTime = String.valueOf(dataSnapshot.getValue(Long.class));

        geoFire.setLocation(serverTime, new GeoLocation(latLng.latitude,latLng.longitude), new GeoFire.CompletionListener() {
            @Override
            public void onComplete(String key, DatabaseError error) {
                if (error != null) {
                    Log.v("Informe","There was an error saving the location to GeoFire: " + error);
                } else {
                    Log.v("Informe","Location saved on server successfully!");
                }
            }
        });
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
};
dbRef.child("serverTime").addListenerForSingleValueEvent(eventListener);

addListenerForSingleValueEvent 解决了你的问题。