我尝试将GeoLocations
与GeoFire
保存在Firebase中,GeoLocation
的密钥必须是服务器时间戳。所以数据模型如下:
{
"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) {
}
});
答案 0 :(得分:1)
要解决此问题,请使用以下代码:
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
解决了您的问题。
答案 1 :(得分:0)
如果要在serverTime = String.valueOf(dataSnapshot.getValue());
处设置断点,则ValueEventListener会执行两次
你会清楚地看到它,
为什么会这样?
因为您的dbRef.child("serverTime").setValue(ServerValue.TIMESTAMP);
是异步的,
应用程序继续运行并设置一个新的valueEventListener,
将立即调用dataSnapshot
中没有任何数据然后,当你的async'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) {
}
});
}
});