如何使用 Firebase 向用户检索附近的面包店 [关闭]

Posted

技术标签:

【中文标题】如何使用 Firebase 向用户检索附近的面包店 [关闭]【英文标题】:How can I retrieve nearby bakeries to users using firebase [closed] 【发布时间】:2020-05-02 19:20:47 【问题描述】:

我知道这个问题被问了一遍又一遍,但我似乎无法得到一个好的答案。我正在尝试根据用户位置检索数据。例如,假设我的数据库有一个面包店列表。每个面包店都有一个地址,经纬度,邮政编码,城市,州。现在我想向顾客展示所有的面包店,但只有那些在他们附近的面包店让我们说 5 英里外我将如何去做。过去几天我一直在寻找答案,但似乎没有任何效果。我什至尝试了this 回答我在堆栈溢出上看到的并且它不起作用。请有人帮我解决这个问题。下面是我的代码

//这个页面是用户注册后会自动保存经纬度和Geohash等的地方

     mFusedLocationClient.getLastLocation()
                .addOnSuccessListener(this, new OnSuccessListener<Location>() 
                    @Override
                    public void onSuccess(final Location location) 
                        // Got last known location. In some rare situations this can be null.
                        if (location != null) 
                            // Logic to handle location object
                            Double latittude = location.getLatitude();
                            Double longitude = location.getLongitude();

                            String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
                            DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference("Users");
                            DatabaseReference update = rootRef.child(uid);
                            GeoFire geoFire=new GeoFire(rootRef);

                            geoFire.setLocation("latandlong", new GeoLocation(location.getLatitude(), location.getLongitude()), new GeoFire.CompletionListener() 
                                @Override
                                public void onComplete(String key, DatabaseError error) 
                                    if (error != null) 
                                        System.err.println("There was an error saving the location to GeoFire: " + error);
                                     else 
                                        System.out.println("Location saved on server successfully!");
                                    
                                
                            );


                            geoFire.getLocation("latandlong", new LocationCallback() 
                                @Override
                                public void onLocationResult(String key, GeoLocation location) 
                                    if (location != null) 
                                        System.out.println(String.format("The location for key %s is [%f,%f]", key, location.latitude, location.longitude));
// save longitude and latitude to db

                                        String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
                                        DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
                                        DatabaseReference update = rootRef.child("Users").child(uid);
                                        Double longi = location.longitude;
                                        Double lat = location.latitude;




                                        update.child("latandlong").setValue(location.latitude+ "," +location.longitude);
                                        //update.child("longitude").setValue(longi);
                                        //update.child("latitude").setValue(lat);
                                     else 
                                        System.out.println(String.format("There is no location for key %s in GeoFire", key));
                                    
                                

                                @Override
                                public void onCancelled(DatabaseError databaseError) 
                                    System.err.println("There was an error getting the GeoFire location: " + databaseError);
                                
                            );



     protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_news_feed);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);



        menuItem=(MenuItem)findViewById(R.id.item_sign_in);




        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);


        recycler=findViewById(R.id.recyclerView);
        recycler.setLayoutManager(new LinearLayoutManager(this));

        final DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();

        mFusedLocationClient.getLastLocation().addOnSuccessListener(new OnSuccessListener<Location>() 
            @Override
            public void onSuccess(Location location) 

                Double lat=location.getLatitude();
                Double longi=location.getLongitude();

                firebaseDatabase=FirebaseDatabase.getInstance().getReference("Users");
                GeoFire geoFire=new GeoFire(firebaseDatabase.child("latandlong"));

                GeoQuery geoQuery=geoFire.queryAtLocation(new GeoLocation(lat,longi),5);

                geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() 
                    @Override
                    public void onKeyEntered(String key, GeoLocation location) 
                        firebaseDatabase.child(key).addValueEventListener(new ValueEventListener() 
                            @Override
                            public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
                                if(dataSnapshot.exists())
                                    list=new ArrayList<UserInformation>();

                                    for(DataSnapshot dataSnapshot1:dataSnapshot.getChildren())
                                        UserInformation uuu=dataSnapshot1.getValue(UserInformation.class);
                                        list.add(uuu);

                                    
                                

                                adapter=new MyAdapter(NewsFeedActivity.this,list);
                                recycler.setAdapter(adapter);

                            

                            @Override
                            public void onCancelled(@NonNull DatabaseError databaseError) 

                            
                        );
                    

                    @Override
                    public void onKeyExited(String key) 

                    

                    @Override
                    public void onKeyMoved(String key, GeoLocation location) 

                    

                    @Override
                    public void onGeoQueryReady() 

                    

                    @Override
                    public void onGeoQueryError(DatabaseError error) 

                    
                );




            
        );

【问题讨论】:

既然您已经在使用 GeoFire,那么您就有了适合这项工作的工具。您当前的代码有什么问题?具体来说:当您在调试器中运行此代码时,哪一行没有按照您的预期执行? @FrankvanPuffelen 非常感谢您的回复。当我运行我的代码时,我没有收到任何错误。我得到一个空白页。没有结果显示 在每一步都添加Logs,看看您在哪一部分没有得到预期的结果,如果您感到困惑,请使用Logs更新您的问题 @GCode22 你需要做的还不止这些。如果你在GeoQuery geoQuery=geoFire.queryAtLocation( 上设置一个断点,它会被执行吗? latlongi 的值是多少?如果您在onKeyEntered 内的第一行设置断点并运行,那么该行是否会被执行?有了key? @FrankvanPuffelen 没有执行任何操作。 longi 取当前经度,lat 取当前纬度 【参考方案1】:

首先,您需要检查该位置的数据是否已添加到 geofire。 您可以在将面包店数据添加到 Firebase 时添加该数据,如下所示

geoFire.setLocation("your key", new GeoLocation(37.7853889, -122.4056973));

geofire 查询方法是以公里而不是英里为单位的距离,因此您必须将 5 英里转换为公里。

GeoQuery geoQuery=geoFire.queryAtLocation(new GeoLocation(lat,longi),5); //distance in km

【讨论】:

感谢您的回复。我做了类似的事情。问题是当我尝试检索该范围内的数据时,我没有得到任何结果。事实上,什么都没有被执行。 您确定 geofire 中存储了数据吗?并且正在执行位置的 onSuccess 方法? 我刚刚编辑了我的问题,并添加了我的 firebase 数据库外观的屏幕截图。我相信它正在被执行 我认为您使用了错误的 geofire 节点。您使用的是“latandlong”,但实际上您的节点名称是“location”。 我更改了它以查看是否是问题所在,但没有任何效果。我可能错了,如果我错了,请告诉我,但这是否是因为在那个距离内可能没有结果?【参考方案2】:

这是初始化 GeoFire 的方式:

firebaseDatabase=FirebaseDatabase.getInstance().getReference("Users");
GeoFire geoFire=new GeoFire(firebaseDatabase.child("latandlong"));

这意味着在您的数据库中,您应该有一个节点/Users/latandlong下您有一个节点,其中包含您要跟踪的每个键的 geohash 和纬度/经度。所以:

Users: 
  latandlong: 
    "IEvLcwll....SQkbp2": 
      g: "..."
      l:  0: ..., 1: ... 
    
  

此结构与您共享的屏幕截图中的不同,因为您缺少 key 级别:"IEvLcwll....SQkbp2"。这解释了为什么您在 geoFire 上触发的任何地理查询都找不到任何键。

我强烈建议阅读 GeoFire 文档:

    如何initialize the GeoFire object,您通常希望将其指向***节点。 然后是set the location data for a specific key,这将成为您在上一步中设置的***节点下的子节点。

只有正确完成这两个步骤后,您才能execute a geoquery against the data。

【讨论】:

我注意到你关闭了我的问题。我已经编辑了我拥有的屏幕截图。我做了一些改变。我没有将经度和纬度加在一起,而是分别添加。我仍然没有得到任何结果。什么都没有执行。 这对我来说仍然是一样的,这就是我在回答中试图解释的:您以错误的格式编写数据,这意味着您的地理查询无法工作。除了我上面概述的之外,没有其他解决方法。 抱歉所有问题,我知道你是一个忙碌的人,我真的很想得到这个,我只需要有人帮助我解决这个问题。好的,我更新了屏幕截图,您可以看到该节点位于 /Users/latandlong 中。现在我正在尝试检索 3 英里内的数据,但没有得到任何结果。我正在真实设备上进行测试。 你的结构看起来还是一样的。我在回答中进一步阐明了所需的结构。如果您按照有关设置对象位置的文档进行操作,您最终会得到所需的结构。 您正在呼叫geoFire.setLocation("latandlong", new GeoLocation(...,这意味着您正在为一个键设置位置latandlong。此外,您正在/Users 上创建GeoFire 实例,您似乎还保留了有关用户的其他数据。 GeoFire 通常将地理信息与有关用户的其他信息分开,至少在我使用它时是这样。但是文档应该会告诉你在那里做什么。

以上是关于如何使用 Firebase 向用户检索附近的面包店 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何使用firebase作为数据库在android中获取附近的用户名?

如何让用户在我在 geofire、Firebase 的位置附近

按用户位置与 Firebase 附近的距离对数组进行排序

使用 Firebase 可调用函数时如何检索用户的身份验证数据?

从 firebase 检索数据并设置 VC 以匹配用户偏好

使用 Firebase 存储和检索位置