首页 文章

Geofire - 找不到位置

提问于
浏览
7

如何使用Geo Queries获取接近传递 GeoLocation(double lat, double lng) 的所有位置 . 我有以下代码(它没有发生):

public void setCurrentLatLng(double lat, double lng){
    this.lat = lat;
    this.lng = lng;
    GeoLocation geoLocation = new GeoLocation(lat, lng);
    updateCurrenLocation(geoLocation);
    GeoQuery geoQuery = geoFire.queryAtLocation(geoLocation, 8f);
    geoQuery.addGeoQueryDataEventListener(new GeoQueryDataEventListener() {

        @Override
        public void onDataEntered(DataSnapshot dataSnapshot, GeoLocation location) {
            Log.d("geoQuery","onDataEntered "+dataSnapshot.toString());
            // ...
        }

        @Override
        public void onDataExited(DataSnapshot dataSnapshot) {
            Log.d("geoQuery","onDataExited "+dataSnapshot.toString());
            // ...
        }

        @Override
        public void onDataMoved(DataSnapshot dataSnapshot, GeoLocation location) {
            Log.d("geoQuery","onDataMoved "+dataSnapshot.toString());
            // ...
        }

        @Override
        public void onDataChanged(DataSnapshot dataSnapshot, GeoLocation location) {
            Log.d("geoQuery","onDataChanged "+dataSnapshot.toString());
            // ...
        }

        @Override
        public void onGeoQueryReady() {
            // ...
            Log.d("geoQuery","onGeoQueryReady");
        }

        @Override
        public void onGeoQueryError(DatabaseError error) {
            Log.d("geoQuery","onGeoQueryError");
            // ...
        }

    });
    this.setChanged();
    notifyObservers();
    this.clearChanged();
    Log.d("update","clearChanged");
}

这是我的火力基础数据:
enter image description here

我想我可以根据需要修改数据结构 .

日志

09-12 08:55:33.818 17710-17710/es.rchampa.weirdo D/geoQuery: lat=40.4430883 lng=-3.721805
09-12 08:55:33.982 17710-17710/es.rchampa.weirdo D/geoQuery: lat=40.4430883 lng=-3.721805
09-12 08:55:33.986 17710-17710/es.rchampa.weirdo D/geoQuery: onGeoQueryReady
09-12 08:55:34.025 17710-17710/es.rchampa.weirdo D/geoQuery: onGeoQueryReady

Gradle文件

....
// Firebase
implementation 'com.google.firebase:firebase-database:16.0.1'
implementation 'com.google.firebase:firebase-storage:16.0.1'
implementation 'com.google.firebase:firebase-auth:16.0.3'
implementation 'com.google.firebase:firebase-crash:16.2.0'
implementation 'com.google.firebase:firebase-core:16.0.3'

// Firebase UI
implementation 'com.firebaseui:firebase-ui-database:1.2.0'

//Firebase GeoFire
implementation 'com.firebase:geofire-android:2.3.1'

// Google Play Services
implementation 'com.google.android.gms:play-services-auth:16.0.0'
implementation 'com.google.android.gms:play-services-maps:15.0.1'
implementation 'com.google.android.gms:play-services-location:15.0.1'
....

更新

如果您愿意,我可以授予访问我的私人仓库的权限 .

3 回答

  • 2

    你传递值 8f (浮动)为 radius ,而 radius 应该是 8.0dDouble.valueOf(8.0) ,其中 MAX_SUPPORTED_RADIUS 等于 8587 千米 .

    虽然实际问题是 GeoFire 已经需要知道 .child("location") ,但是用 Reference 代表它是不可能的 . 只有 DataSnapshotgetChildren() .

    底线是:

    你必须创建一个单独的位置参考,以避免嵌套 . 尽管如此,您仍然可以为这些节点使用相关的uid密钥(或者至少将其添加为子节点),以便能够在用户参考中查找 . 它是两个参考文献之间的1:1关系 .

    所以这是一个工作 Java 的例子,因为......

    我们假设以下结构(如上所述):

    {
      "locations" : {
        "CR88aa9gnDfJYYGq5ZTMwwC38C12" : {
          ".priority" : "9q8yywdgue",
          "g" : "9q8yywdgue",
          "l" : [ 37.7853889, -122.4056973 ]
        }
      },
      "users" : {
        "CR88aa9gnDfJYYGq5ZTMwwC38C12" : {
          "displayName" : "user 01",
          ...
        }
      }
    }
    

    数据库规则应该 .indexOnlocations field g 设置:

    {
      "rules": {
        ...
        "locations": {
          ".indexOn": "g"
        }
      }
    }
    

    模块中的依赖项 build.gradle

    dependencies {
        ...
        api "com.firebase:geofire-android:2.3.1"
    }
    

    这表明,如何通过 GeoQuery 结果获取用户的快照;

    注意 GeoQueryEventListener 而不是 GeoQueryDataEventListener

    public class GeofireActivity extends AppCompatActivity {
    
        private static final String LOG_TAG = GeofireActivity.class.getSimpleName();
    
        private DatabaseReference refBase     = null;
        private DatabaseReference refLocation = null;
        private DatabaseReference refUser     = null;
    
        private GeoFire geoFire = null;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            this.setContentView(R.layout.fragment_geofire);
            this.setReferences();
        }
    
        private void setReferences() {
            this.refBase = FirebaseDatabase.getInstance().getReference();
            this.refUser = refBase.child("users");
            this.refLocation = refBase.child("locations");
            this.geoFire = new GeoFire(this.refLocation);
        }
    
        private void searchNearby(double latitude, double longitude, double radius) {
            this.searchNearby(new GeoLocation(latitude, longitude), radius);
        }
    
        private void searchNearby(GeoLocation location, double radius) {
    
            GeoQuery geoQuery = this.geoFire.queryAtLocation(location, radius);
            geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
    
                @Override
                public void onKeyEntered(String key, GeoLocation location) {
    
                    String loc = String.valueOf(location.latitude) + ", " + String.valueOf(location.longitude);
                    Log.d(LOG_TAG, "onKeyEntered: " + key + " @ " + loc);
    
                    /* once the key is known, one can lookup the associated record */
                    refUser.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
    
                        @Override
                        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                            Log.d(LOG_TAG, "onDataChange: " + dataSnapshot.toString());
                        }
    
                        @Override
                        public void onCancelled(@NonNull DatabaseError firebaseError) {
                            Log.e(LOG_TAG, "onCancelled: " + firebaseError.getMessage());
                        }
                    });
                }
    
                @Override
                public void onKeyExited(String key) {
                    Log.d(LOG_TAG, "onKeyExited: " + key);
                }
    
                @Override
                public void onKeyMoved(String key, GeoLocation location) {
                    Log.d(LOG_TAG, "onKeyMoved: " + key);
                }
    
                @Override
                public void onGeoQueryReady() {
                    Log.d(LOG_TAG, "onGeoQueryReady");
                }
    
                @Override
                public void onGeoQueryError(DatabaseError error) {
                    Log.e(LOG_TAG, "onGeoQueryError" + error.getMessage());
                }
            });
        }
    }
    

    为了保持完整性,当删除用户记录时,需要删除关联的位置记录 - 否则会导致密钥无法再查找 .

  • 2

    问题是你根据问题传递半径https://github.com/firebase/geofire-java/issues/72

    double radius = 8589; // Fails
    //  double radius = 8587.8; //Passes
    

    尝试传递这样的 Value 这可能会有所帮助

    //GeoQuery geoQuery = geoFire.queryAtLocation(geoLocation, 8f);
    GeoQuery geoQuery = geoFire.queryAtLocation(geoLocation, radius);
    

    将值8f(float)作为半径,而半径应该是8.0d或Double.valueOf(8.0),其中MAX_SUPPORTED_RADIUS等于8587公里 .

  • 2

    因为它现在正好 geofire 作为一个索引来打开地理查询,并提供你想要的文件的密钥(将存储在一个单独的"collection") .

    你应该使用 geofire 和一个单独的"collection"(称之为 usersLocations

    DatabaseReference ref = FirebaseDatabase.getInstance().getReference("usersLocations");
    GeoFire geoFire = new GeoFire(ref);
    

    现在您可以将它用作 users 的索引,并可以像这样添加项目 .

    geoFire.setLocation('QymlMpC0Zc', new GeoLocation(40.2334983, -3.7185183));
    

    您的Firebase RTDB现在看起来像这样:

    {
       'users': {
            'QymlMpC0Zc': {
                // All your data here
            }
        },
       'usersLocations': {
            'QymlMpC0Zc': {
                'g': 'ezjkgkk305',
                'l': {
                    '0': 40.2334983,
                    '1': -3.7185183
                }
            }
        }
    }
    

    所以最后当你对你的_1470470进行查询时,你最终会解雇你拥有的任何听众 .

    As a small note... I am not a Java developer, but I do use/know geofire in general. Hopefully my bits of advice/thoughts will be helpful.

相关问题