【问题标题】:Firebase (GeoFire) saves data twiceFirebase (GeoFire) 两次保存数据
【发布时间】:2018-01-12 11:24:12
【问题描述】:

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

{
  "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) {

                    }
                });

【问题讨论】:

  • 什么是 geoFire ref?
  • @Nirel 抱歉,我已经编辑了帖子并添加了它。

标签: android firebase firebase-realtime-database geofire


【解决方案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 解决了你的问题。

【讨论】:

  • 感谢 Alex,但这不起作用,因为 .setLocation() 方法需要一个字符串作为第一个参数,而 ServerValue.TIMESTAMP 是一个 。另外,如果我尝试解析它,它不会起作用,因为 ServerValue.TIMESTAMP 是一个必须在服务器端运行的函数。
  • 我明白了。请告诉我,为什么您需要 GeoLocation 的键作为服务器时间戳?
  • 这是我项目的数据模型中的一项要求,以便在需要位置插入时间时执行操作。
  • 行不通,亚历克斯。非常感谢 :) 你是怎么知道的?只是好奇。
  • addListenerForSingleValueEvent 只侦听一次事件,这就是您所需要的。干杯!
【解决方案2】:

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) {

                }
            });
}

});

【讨论】:

  • 嘿 Nirel,我已经尝试过您的解决方案,但它仍然设置了 2 个值。所以我想到了 dataSnapshot.exists() 解决方案,但我想知道它如何帮助解决这个问题,因为它在数据库中插入了 2 个不同的值(对不起,它们没有重复,我的错),谢谢 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多