1

I know that this question has been asked over and over but I just can't seem to get a good answer. I am trying to retrieve data based off of the users location. For example lets say my database has a list of bakeries. Each bakery has an address, the longitude and latitude,postal code,city,state. Now I want to display all of the bakeries to customers but only the ones that are around their area lets say 5 miles away how would I go about doing that. I've been looking for answers for the past few days and nothing seems to be working. I even tried this answer I saw on Stack overflow and its not working. Someone please please please help me with this. Below is my code Firebase Database

//This page is where after the user registers it will automatically save the longitude and latitude and that's when it will save the Geohash etc

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

                    }
                });




            }
        });
GCode22
  • 47
  • 6
  • Since you're already using GeoFire, you have the right tool for the job. What doesn't work about your current code? Specifically: when you run this code in a debugger, what line doesn't do what you expected it to do? – Frank van Puffelen Jan 16 '20 at 00:32
  • @FrankvanPuffelen Thank you so much for replying. when I run my code I don't get any error. I get a blank page. No results is being shown – GCode22 Jan 16 '20 at 02:31
  • 1
    Add `Logs` on every step and see on which part you are not getting what is expected, also if you are confuse, update your question with `Logs` – Rahul Gaur Jan 16 '20 at 03:57
  • @GCode22 You'll need to do a bit more than that. If you put a breakpoint on `GeoQuery geoQuery=geoFire.queryAtLocation(`, does it get executed? What are the values of `lat` and `longi`? If you put a breakpoint on the first line inside `onKeyEntered` and run, does that line ever get executed? With that `key`? – Frank van Puffelen Jan 16 '20 at 04:15
  • @FrankvanPuffelen No nothing gets executed. The value longi takes the current longitude and the lat takes the current latitude – GCode22 Jan 16 '20 at 04:35
  • If the `GeoQuery geoQuery=geoFire.queryAtLocation(` doesn't get executed, there's no way you'll get results from a certain range. – Frank van Puffelen Jan 16 '20 at 04:55
  • @FrankvanPuffelen I'm not even understanding why its not executing. While looking at my code do you see anything that I'm doing wrong? Can you show me how everything suppose to be cause I'm really not understanding why its not executing. – GCode22 Jan 16 '20 at 05:28
  • The debugger is your best option here. Put a breakpoint on `mFusedLocationClient.getLastLocation().addOnSuccessListener`, and see if that hits. If it does, put a breakpoint inside that success listener, and see if that gets called. That way you can find what operation is failing. – Frank van Puffelen Jan 16 '20 at 14:48
  • @FrankvanPuffelen Take a look at my code that is exactly what I did sir. And it doesn't tell me anything. wow this crazy. Does if have to do with the fact that there is not results within that distance? – GCode22 Jan 16 '20 at 17:41
  • @GCode22 Sorry for closing this, but it appears too abstract to tell why or how to fix it. Also see this [answer](https://stackoverflow.com/questions/52249425/geofire-not-found-locations/52289410#52289410) of mine, which is similar - and it shows, what exactly we mean by "add logging". – Martin Zeitler Jan 16 '20 at 18:23
  • @FrankvanPuffelen thank you so much for your help I will take a look at that answer. – GCode22 Jan 16 '20 at 20:00

2 Answers2

4

First of all you need to check that data for that location is added to geofire or not. You can add that data while adding bakery data to firebase like below

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

and geofire query method takes distance in km not miles so you have to convert 5 miles to km.

GeoQuery geoQuery=geoFire.queryAtLocation(new GeoLocation(lat,longi),5); //distance in km
Nehal Godhasara
  • 787
  • 3
  • 7
  • Thank you for responding. I sort of did something like that. The problem is when I try to retrieve data within that range I don't get any results. As a matter of fact nothing is being executed. – GCode22 Jan 16 '20 at 05:39
  • are you sure there is data stored in geofire? and onSuccess method of location is being executed? – Nehal Godhasara Jan 16 '20 at 06:04
  • I just edited my question and I added a screen shot of how my firebase database looks. I believe it is being executed – GCode22 Jan 16 '20 at 06:22
  • I think you are using wrong geofire node. you are using "latandlong" but actually your node name is "location". – Nehal Godhasara Jan 16 '20 at 06:39
  • I changed that to see if that was the problem but nothing works. I might be wrong on this tell me if I am but is it cause maybe there's no results within that distance? – GCode22 Jan 16 '20 at 17:44
1

This is how you initialize GeoFire:

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

This means that in your database you're expected to have a node /Users/latandlong, under which you have a node with the geohash and lat/lon for each key you want to track. So:

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

This structure is different from what's in the screenshot you shared, as you are missing the key level: "IEvLcwll....SQkbp2". This explains why any geoquery you fire on geoFire won't find any keys.

I highly recommend reading the GeoFire documentation on:

  1. How to initialize the GeoFire object, which you'll typically want to point to a top-level node.
  2. Then set the location data for a specific key, which will then become a child node under the top-level node you set in the previous step.

Only once you've done these two steps correctly, will you be able to execute a geoquery against the data.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I noticed you closed my question. I've edited the screen shot picture that I had. I made some changes. Instead of adding the longitude and latitude together I added them separately. I'm still not getting any results. Nothing is executing. – GCode22 Jan 16 '20 at 22:28
  • That still looks the same to me, which is what I tried to explain in my answer: you're writing the data in the wrong format, which means your geoquery can't work. There's no fix outside of what I outlined above. – Frank van Puffelen Jan 17 '20 at 00:06
  • Sorry for all the questions I know you're a busy man I'm just really trying to get this and I just need someone to help me through this. Ok I updated the screen shot as you can see the node is in the /Users/latandlong. Now I'm trying to retrieve the data within 3 miles but I don't get any results. I'm testing this on a real device. – GCode22 Jan 17 '20 at 04:50
  • The structure you have still looks the same. I further clarified the required structure in my answer. If you follow the documentation on setting the location of an object, you'll end up with the rquired structure. – Frank van Puffelen Jan 17 '20 at 14:11
  • Ok last thing Frank. I see what you're talking about the key level I'm just now realizing I don't see it either. I have one piece of information to show you. This page is where after the user registers it will automatically save the longitude and latitude and that's when it will save the Geohash etc. Please take a look at it. I think the problem is there – GCode22 Jan 17 '20 at 21:15
  • 1
    You're calling `geoFire.setLocation("latandlong", new GeoLocation(...`, which means you're setting the location for one key only `latandlong`. In addition, you're creating the `GeoFire` instance on `/Users`, where you also seem to be keepign other data about users. GeoFire typically separates the geo-info from the other information about users, at least when I used it. But the docs should tell you what to do there. – Frank van Puffelen Jan 17 '20 at 22:37
  • I have good news... I finally got it... the whole time I was missing this code GeoFire geoFire = new GeoFire(latandlong); I can't believe I missed it. Now everything is working fine. Thank you so much for your patience and your help. – GCode22 Jan 19 '20 at 06:57