Search code examples
javaandroidfirebasefirebase-realtime-databasegeofire

Firebase / GeoQuery - Maximum Radius IF Statement


So I have been trying for a while now to implement a way in which I can update the user if there are no tradesman found or if there are no tradesman within a maximum radius. So the app basically searches for tradesman available within the Firebase and matches with the closest one based on their latitude&longitude. If none are found within 1 mile, it then increments to 2 and so on.

What I have been struggling to implement is a way to say if there is no tradesman available within the firebase or if there are no tradesman available within a certain radius so once it increments to say 10 miles stop and return no tradesman found.

This is the code I have now which searches for the tradesman and increments the radius, but will never stop searching unless I click a button which ends the search, so I need a way to end the search without clicking the button.

private int radius = 1; // 1 radius (mile or km not sure)
private int max_radius = 15;
private Boolean tradesmanFound = false;
private String tradesmanFoundID;
GeoQuery geoQuery;

private void getClosestTradesman() {
    DatabaseReference tradesmanLocation = FirebaseDatabase.getInstance().getReference().child("TradesmanAvailable");

    GeoFire geoFire = new GeoFire(tradesmanLocation);
    geoQuery = geoFire.queryAtLocation(new GeoLocation(customerLocation.latitude, customerLocation.longitude), radius);
    geoQuery.removeAllListeners();

    geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
        @Override
        public void onKeyEntered(String key, GeoLocation location) {
            if (!tradesmanFound && requestBol) {
                DatabaseReference customerDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child("Tradesman").child(key);
                customerDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        if (dataSnapshot.exists() && dataSnapshot.getChildrenCount() > 0) {
                            Map<String, Object> tradesmanMap = (Map<String, Object>) dataSnapshot.getValue();
                            if (tradesmanFound) {
                                return;
                            }

                            if (tradesmanMap.get("Trade").equals(tradeType)) {
                                tradesmanFound = true;
                                tradesmanFoundID = dataSnapshot.getKey();

                                DatabaseReference tradesmanRef = FirebaseDatabase.getInstance().getReference().child("Users").child("Tradesman").child(tradesmanFoundID).child("CustomerRequest");
                                String customerID = FirebaseAuth.getInstance().getCurrentUser().getUid();
                                HashMap map = new HashMap();
                                map.put("CustomerRequestID", customerID);
                                tradesmanRef.updateChildren(map);

                                getTradesmanLocation();
                                getTradesmanInfo();
                                isRequestFinished();
                                requestTradesmanBtn.setText("Looking for Tradesman's Location...");
                            }
                        }
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {
                    }
                });
            }
        }

        @Override
        public void onKeyExited(String key) {

        }

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

        }

        @Override
        public void onGeoQueryReady() {
            if (!tradesmanFound) {

                radius++;
                getClosestTradesman();

            }
        }

        @Override
        public void onGeoQueryError(DatabaseError error) {

        }
    });
}

This has been bugging me for a while as it seems like something pretty simple and straightforward in my head, so any help will relive a lot of stress. Thanks


Solution

  • You're really close. When the geoquery is done loading its initial data, it calls onGeoQueryReady, which you right now have as:

    @Override
    public void onGeoQueryReady() {
        if (!tradesmanFound) {
    
            radius++;
            getClosestTradesman();
    
        }
    }
    

    So if no tradesmen were found, you start a new query with a larger radius. There two things missing from this:

    1. You should only start a new query if you haven't gotten to the maximum range yet.
    2. You should cancel the existing geoquery that was just completed, otherwise you'll end up with many overlapping geoqueries.

    So in code:

    @Override
    public void onGeoQueryReady() {
        if (!tradesmanFound && radius < 10) {
    
            geoQuery.removeAllListeners();
    
            radius++;
            getClosestTradesman();
    
        }
    }
    

    I know you already have a call to geoQuery.removeAllListeners(), but where you currently have it actually doesn't do anything.


    I noticed this in your code:

    private int radius = 1; // 1 radius (mile or km not sure)
    

    The radius is in kilometers as can be seen in the example query in the docs.