Firebase (GeoFire) 两次保存数据
Firebase (GeoFire) saves data twice
我试图在 Firebase 中用 GeoFire
保存 GeoLocations
,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) {
}
});
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
解决了你的问题。
我试图在 Firebase 中用 GeoFire
保存 GeoLocations
,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) {
}
});
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
解决了你的问题。